├── .github
├── ISSUE_TEMPLATE
│ ├── BUG-REPORT.yml
│ ├── ENHANCEMENT.yml
│ ├── FEATURE-REQUEST.md
│ └── config.yml
└── workflows
│ ├── integration_tests.yml
│ ├── lint_markdown.yml
│ ├── source_clear_cron.yml
│ ├── swift.yml
│ ├── ticket_reference_check.yml
│ └── unit_tests.yml
├── .gitignore
├── .swiftlint.yml
├── CHANGELOG.md
├── CODEOWNERS
├── CONTRIBUTING.md
├── DemoObjCApp
├── AppDelegate.h
├── AppDelegate.m
├── Customization
│ ├── CustomLogger.h
│ └── CustomLogger.m
├── DemoObjcApp.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── DemoObjciOS.xcscheme
│ │ └── DemoObjctvOS.xcscheme
├── DemoObjciOS
│ ├── Base.lproj
│ │ └── iOSMain.storyboard
│ └── Info.plist
├── DemoObjctvOS
│ ├── Base.lproj
│ │ └── tvOSMain.storyboard
│ └── Info.plist
├── Samples
│ ├── SamplesForAPI.h
│ └── SamplesForAPI.m
├── VariationViewController.h
├── VariationViewController.m
└── main.m
├── DemoSwiftApp
├── AppDelegate.swift
├── Customization
│ └── CustomLogger.swift
├── DemoSwiftApp.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── DemoSwiftiOS.xcscheme
│ │ ├── DemoSwifttvOS.xcscheme
│ │ └── DemoSwiftwatchOS.xcscheme
├── DemoSwiftiOS
│ ├── Base.lproj
│ │ └── iOSMain.storyboard
│ └── Info.plist
├── DemoSwifttvOS
│ ├── Base.lproj
│ │ └── tvOSMain.storyboard
│ └── Info.plist
├── DemoSwiftwatchOS WatchKit App
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ └── Interface.storyboard
│ └── Info.plist
├── DemoSwiftwatchOS WatchKit Extension
│ ├── Assets.xcassets
│ │ └── Contents.json
│ ├── ExtensionDelegate.swift
│ ├── Info.plist
│ └── InterfaceController.swift
├── Samples
│ └── SamplesForAPI.swift
├── SharedResources
│ ├── DemoSwiftiOS
│ │ └── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-1024.png
│ │ │ ├── Icon-20.png
│ │ │ ├── Icon-20@2x.png
│ │ │ ├── Icon-20@3x.png
│ │ │ ├── Icon-40@2x.png
│ │ │ ├── Icon-40@3x.png
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-72.png
│ │ │ ├── Icon-72@2x.png
│ │ │ ├── Icon-76.png
│ │ │ ├── Icon-76@2x.png
│ │ │ ├── Icon-83.5@2x.png
│ │ │ ├── Icon-Small-50.png
│ │ │ ├── Icon-Small-50@2x.png
│ │ │ ├── Icon-Small.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ ├── Icon-Small@3x.png
│ │ │ ├── Icon-iPad-20@2x.png
│ │ │ ├── Icon-iPad-settings.png
│ │ │ ├── Icon-iPad-settings@2x.png
│ │ │ ├── Icon-iPad-spotlight.png
│ │ │ ├── Icon-iPad-spotlight@2x.png
│ │ │ ├── Icon.png
│ │ │ └── Icon@2x.png
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.launchimage
│ │ │ ├── Contents.json
│ │ │ ├── image1_1024x768.png
│ │ │ ├── image1_1536x2048.png
│ │ │ ├── image1_2048x1536.png
│ │ │ ├── image1_640x1136.png
│ │ │ ├── image1_640x960.png
│ │ │ ├── image1_768x1024.png
│ │ │ ├── image_1024x748.png
│ │ │ ├── image_1024x768.png
│ │ │ ├── image_1242x2208.png
│ │ │ ├── image_1536x2008.png
│ │ │ ├── image_1536x2048.png
│ │ │ ├── image_2048x1496.png
│ │ │ ├── image_2048x1536.png
│ │ │ ├── image_2208x1242.png
│ │ │ ├── image_320x480.png
│ │ │ ├── image_640x1136.png
│ │ │ ├── image_640x960.png
│ │ │ ├── image_750x1334.png
│ │ │ ├── image_768x1004.png
│ │ │ └── image_768x1024.png
│ │ │ ├── background_confirmation.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_confirmation@1x.png
│ │ │ ├── background_confirmation@2x.png
│ │ │ └── background_confirmation@3x.png
│ │ │ ├── background_error.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_error@1x.png
│ │ │ ├── background_error@2x.png
│ │ │ └── background_error@3x.png
│ │ │ ├── background_variA.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_variA@1x.png
│ │ │ ├── background_variA@2x.png
│ │ │ └── background_variA@3x.png
│ │ │ ├── background_variB-marina.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_variB-marina@1x.png
│ │ │ ├── background_variB-marina@2x.png
│ │ │ └── background_variB-marina@3x.png
│ │ │ └── logo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── logo@1x.png
│ │ │ ├── logo@2x.png
│ │ │ └── logo@3x.png
│ ├── DemoSwifttvOS
│ │ └── Assets.xcassets
│ │ │ ├── App Icon & Top Shelf Image.brandassets
│ │ │ ├── App Icon - Large.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ └── icon-large_back.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ └── icon-large_front.png
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon-large_middle.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── App Icon - Small.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ ├── icon-small_back.png
│ │ │ │ │ │ └── icon-small_back@2x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ ├── icon-small_front.png
│ │ │ │ │ │ └── icon-small_front@2x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer
│ │ │ │ │ ├── Content.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── icon-small_middle.png
│ │ │ │ │ └── icon-small_middle@2x.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Top Shelf Image Wide.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon-top_shelf_wide.png
│ │ │ │ └── icon-top_shelf_wide@2x.png
│ │ │ └── Top Shelf Image.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon-top_shelf.png
│ │ │ │ └── icon-top_shelf@2x.png
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.launchimage
│ │ │ ├── Contents.json
│ │ │ └── LaunchImage.png
│ │ │ ├── background_confirmation.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_confirmation@1x.png
│ │ │ ├── background_confirmation@2x.png
│ │ │ └── background_confirmation@3x.png
│ │ │ ├── background_error.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_error@1x.png
│ │ │ ├── background_error@2x.png
│ │ │ └── background_error@3x.png
│ │ │ ├── background_variA.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_variA@1x.png
│ │ │ ├── background_variA@2x.png
│ │ │ └── background_variA@3x.png
│ │ │ ├── background_variB-marina.imageset
│ │ │ ├── Contents.json
│ │ │ ├── background_variB-marina@1x.png
│ │ │ ├── background_variB-marina@2x.png
│ │ │ └── background_variB-marina@3x.png
│ │ │ └── logo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── logo@1x.png
│ │ │ ├── logo@2x.png
│ │ │ └── logo@3x.png
│ └── Resources
│ │ ├── ProximaNova-Regular.otf
│ │ ├── Roboto-Medium.ttf
│ │ └── demoTestDatafile.json
└── VariationViewController.swift
├── LICENSE
├── OptimizelySwiftSDK.podspec
├── OptimizelySwiftSDK.xcodeproj
├── project.pbxproj
└── xcshareddata
│ ├── xcbaselines
│ ├── 6E636B8B2236C91F00AF3CEF.xcbaseline
│ │ ├── 2564B2A6-3658-41F8-8220-6CC2F6018D25.plist
│ │ └── Info.plist
│ └── 6EBAEB7321E3FEF900D13AA9.xcbaseline
│ │ ├── 97A8F182-0DA1-4499-B20E-185EB633EA3E.plist
│ │ └── Info.plist
│ └── xcschemes
│ ├── OptimizelySwiftSDK-iOS.xcscheme
│ ├── OptimizelySwiftSDK-macOS.xcscheme
│ ├── OptimizelySwiftSDK-tvOS.xcscheme
│ └── OptimizelySwiftSDK-watchOS.xcscheme
├── OptimizelySwiftSDK.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDETemplateMacros.plist
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── Package.swift
├── Podfile
├── README.md
├── Scripts
├── build_all.sh
├── change_header
│ ├── header.template
│ ├── remove_header.awk
│ ├── replace_header.sh
│ └── replace_headers_folder.sh
├── prepare_coveralls_report.sh
├── prepare_simulator.sh
├── run_prep.sh
├── run_release.sh
├── run_unit_tests.sh
├── runtimeVersion.sh
├── test_all.sh
└── update_version.sh
├── Sources
├── CMAB
│ └── CmabClient.swift
├── Customization
│ ├── DefaultDatafileHandler.swift
│ ├── DefaultEventDispatcher.swift
│ ├── DefaultLogger.swift
│ ├── DefaultUserProfileService.swift
│ └── Protocols
│ │ ├── OPTDatafileHandler.swift
│ │ ├── OPTEventDispatcher.swift
│ │ ├── OPTLogger.swift
│ │ └── OPTUserProfileService.swift
├── Data Model
│ ├── Attribute.swift
│ ├── Audience
│ │ ├── AttributeValue.swift
│ │ ├── Audience.swift
│ │ ├── ConditionHolder.swift
│ │ ├── ConditionLeaf.swift
│ │ ├── SemanticVersion.swift
│ │ └── UserAttribute.swift
│ ├── Cmab.swift
│ ├── DispatchEvents
│ │ ├── BatchEvent.swift
│ │ └── EventForDispatch.swift
│ ├── Event.swift
│ ├── Experiment.swift
│ ├── ExperimentCore.swift
│ ├── FeatureFlag.swift
│ ├── FeatureVariable.swift
│ ├── Group.swift
│ ├── Holdout.swift
│ ├── HoldoutConfig.swift
│ ├── Integration.swift
│ ├── Project.swift
│ ├── ProjectConfig.swift
│ ├── Rollout.swift
│ ├── TrafficAllocation.swift
│ ├── Variable.swift
│ └── Variation.swift
├── Extensions
│ ├── Array+Extension.swift
│ ├── ArrayEventForDispatch+Extension.swift
│ ├── DataStoreQueueStackImpl+Extension.swift
│ └── OptimizelyClient+Extension.swift
├── Implementation
│ ├── Datastore
│ │ ├── DataStoreFile.swift
│ │ ├── DataStoreMemory.swift
│ │ ├── DataStoreQueueStackImpl.swift
│ │ └── DataStoreUserDefaults.swift
│ ├── DecisionInfo.swift
│ ├── DecisionReasons.swift
│ ├── DecisionResponse.swift
│ ├── DefaultBucketer.swift
│ ├── DefaultDecisionService.swift
│ ├── DefaultNotificationCenter.swift
│ ├── Events
│ │ └── BatchEventBuilder.swift
│ └── UserProfileTracker.swift
├── ODP
│ ├── LruCache.swift
│ ├── OdpConfig.swift
│ ├── OdpEvent.swift
│ ├── OdpEventApiManager.swift
│ ├── OdpEventManager.swift
│ ├── OdpManager.swift
│ ├── OdpSegmentApiManager.swift
│ ├── OdpSegmentManager.swift
│ ├── OptimizelySdkSettings.swift
│ └── OptimizelySegmentOption.swift
├── Optimizely+Decide
│ ├── OptimizelyClient+Decide.swift
│ ├── OptimizelyDecideOption.swift
│ ├── OptimizelyDecision.swift
│ ├── OptimizelyUserContext+ObjC.swift
│ └── OptimizelyUserContext.swift
├── Optimizely
│ ├── OptimizelyClient+ObjC.swift
│ ├── OptimizelyClient.swift
│ ├── OptimizelyConfig+ObjC.swift
│ ├── OptimizelyConfig.swift
│ ├── OptimizelyError.swift
│ ├── OptimizelyJSON+ObjC.swift
│ ├── OptimizelyJSON.swift
│ ├── OptimizelyLogLevel.swift
│ ├── OptimizelyResult.swift
│ └── VuidManager.swift
├── Protocols
│ ├── BackgroundingCallbacks.swift
│ ├── DataStoreQueueStack.swift
│ ├── OPTBucketer.swift
│ ├── OPTDataStore.swift
│ ├── OPTDecisionService.swift
│ └── OPTNotificationCenter.swift
├── Supporting Files
│ ├── Info.plist
│ ├── Optimizely.h
│ └── PrivacyInfo.xcprivacy
├── Utils
│ ├── AtomicArray.swift
│ ├── AtomicDictionary.swift
│ ├── AtomicProperty.swift
│ ├── Constants.swift
│ ├── HandlerRegistryService.swift
│ ├── LogMessage.swift
│ ├── MurmurHash3.swift
│ ├── NetworkReachability.swift
│ ├── Notifications.swift
│ ├── SDKVersion.swift
│ ├── ThreadSafeLogger.swift
│ └── Utils.swift
└── watchOS
│ └── WatchBackgroundNotifier.swift
├── Tests
├── Info.plist
├── OptimizelyTests-APIs
│ ├── OptimizelyClientTests.swift
│ ├── OptimizelyClientTests_DatafileHandler.swift
│ ├── OptimizelyClientTests_Decide.swift
│ ├── OptimizelyClientTests_Evaluation.swift
│ ├── OptimizelyClientTests_ForcedVariation.swift
│ ├── OptimizelyClientTests_Group.swift
│ ├── OptimizelyClientTests_Init_Async.swift
│ ├── OptimizelyClientTests_Init_Async_Await.swift
│ ├── OptimizelyClientTests_Init_Sync.swift
│ ├── OptimizelyClientTests_Invalid.swift
│ ├── OptimizelyClientTests_ODP.swift
│ ├── OptimizelyClientTests_ObjcAPIs.m
│ ├── OptimizelyClientTests_ObjcOthers.m
│ ├── OptimizelyClientTests_OptimizelyConfig.swift
│ ├── OptimizelyClientTests_OptimizelyConfig_Objc.m
│ ├── OptimizelyClientTests_OptimizelyJSON.swift
│ ├── OptimizelyClientTests_OptimizelyJSON_Objc.m
│ ├── OptimizelyClientTests_Others.swift
│ ├── OptimizelyClientTests_Valid.swift
│ ├── OptimizelyClientTests_Variables.swift
│ ├── OptimizelyErrorTests.swift
│ └── OptimizelyManagerTests_Threading.swift
├── OptimizelyTests-Batch-iOS
│ └── EventDispatcherTests_Batch.swift
├── OptimizelyTests-Common
│ ├── BatchEventBuilderTest.swift
│ ├── BatchEventBuilderTests_Attributes.swift
│ ├── BatchEventBuilderTests_EventTags.swift
│ ├── BatchEventBuilderTests_Events.swift
│ ├── BucketTests_Base.swift
│ ├── BucketTests_BucketVariation.swift
│ ├── BucketTests_ExpToVariation.swift
│ ├── BucketTests_GroupToExp.swift
│ ├── BucketTests_HoldoutToVariation.swift
│ ├── BucketTests_Others.swift
│ ├── CMABClientTests.swift
│ ├── DataStoreTests.swift
│ ├── DatafileHandlerTests.swift
│ ├── DecisionListenerTest_Holdouts.swift
│ ├── DecisionListenerTests.swift
│ ├── DecisionListenerTests_Datafile.swift
│ ├── DecisionReasonsTests.swift
│ ├── DecisionServiceTests_Experiments.swift
│ ├── DecisionServiceTests_Features.swift
│ ├── DecisionServiceTests_Holdouts.swift
│ ├── DecisionServiceTests_Others.swift
│ ├── DecisionServiceTests_UserProfiles.swift
│ ├── DefaultLoggerTests.swift
│ ├── DefaultUserProfileServiceTests.swift
│ ├── EventDispatcherTests.swift
│ ├── LoggerTests.swift
│ ├── LruCacheTests.swift
│ ├── MurmurTests.swift
│ ├── NetworkReachabilityTests.swift
│ ├── NotificationCenterTests.swift
│ ├── OdpEventApiManagerTests.swift
│ ├── OdpEventManagerTests.swift
│ ├── OdpManagerTests.swift
│ ├── OdpSegmentApiManagerTests.swift
│ ├── OdpSegmentManagerTests.swift
│ ├── OptimizelyDecisionTests.swift
│ ├── OptimizelyErrorTests.swift
│ ├── OptimizelyUserContextTests.swift
│ ├── OptimizelyUserContextTests_Decide.swift
│ ├── OptimizelyUserContextTests_Decide_Holdouts.swift
│ ├── OptimizelyUserContextTests_Decide_Legacy.swift
│ ├── OptimizelyUserContextTests_Decide_Reasons.swift
│ ├── OptimizelyUserContextTests_Decide_With_Holdouts_Reasons.swift
│ ├── OptimizelyUserContextTests_ForcedDecisions.swift
│ ├── OptimizelyUserContextTests_ODP.swift
│ ├── OptimizelyUserContextTests_ODP_2.swift
│ ├── OptimizelyUserContextTests_ODP_Aync_Await.swift
│ ├── OptimizelyUserContextTests_ODP_Decide.swift
│ ├── OptimizelyUserContextTests_Objc.m
│ ├── OptimizelyUserContextTests_Performance.swift
│ └── VuidManagerTests.swift
├── OptimizelyTests-DataModel
│ ├── AttributeTests.swift
│ ├── AttributeValueTests.swift
│ ├── AttributeValueTests_Evaluate.swift
│ ├── AudienceTests.swift
│ ├── AudienceTests_Evaluate.swift
│ ├── CmabTests.swift
│ ├── ConditionHolderTests.swift
│ ├── ConditionHolderTests_Evaluate.swift
│ ├── ConditionLeafTests.swift
│ ├── EventForDispatchTests.swift
│ ├── EventTests.swift
│ ├── ExperimentTests.swift
│ ├── FeatureFlagTests.swift
│ ├── FeatureVariableTests.swift
│ ├── GroupTests.swift
│ ├── HoldoutConfigTests.swift
│ ├── HoldoutTests.swift
│ ├── IntegrationTests.swift
│ ├── ProjectConfigTests.swift
│ ├── ProjectTests.swift
│ ├── RolloutTests.swift
│ ├── SemanticVersionTests.swift
│ ├── TrafficAllocationTests.swift
│ ├── UserAttributeTests.swift
│ ├── UserAttributeTests_Evaluate.swift
│ ├── VariableTests.swift
│ └── VariationTests.swift
├── OptimizelyTests-MultiClients
│ ├── AtomicArrayTests.swift
│ ├── AtomicDictionaryTests.swift
│ ├── ConcurrencyTests_SingleClient.swift
│ ├── DatafileHandlerTests_MultiClients.swift
│ ├── EventDispatcherTests_MultiClients.swift
│ ├── HandlerRegistryServiceTests_MultiClients.swift
│ ├── LoggerTests_MultiClients.swift
│ ├── MultiClientsTests.swift
│ ├── NotificationCenterTests_MultiClients.swift
│ ├── ProjectConfigTests_MultiClients.swift
│ └── UserProfileServiceTests_MultiClients.swift
├── OptimizelyTests-Others
│ ├── OtherTests.swift
│ └── ThrowableConditionListTest.swift
├── OptimizelyTests-iOS
│ └── iOSOnlyTests.swift
├── OptimizelyTests-tvOS
│ └── tvOSOnlyTests.swift
├── TestData
│ ├── ab_experiments.json
│ ├── api_datafile.json
│ ├── audience_targeting.json
│ ├── benchmark
│ │ ├── 100_entities.json
│ │ ├── 10_entities.json
│ │ └── 50_entities.json
│ ├── bot_filtering_enabled.json
│ ├── bucketer_test.json
│ ├── bucketer_test2.json
│ ├── bucketer_test3.json
│ ├── bucketing_id.json
│ ├── decide
│ │ └── decide_datafile.json
│ ├── empty_datafile.json
│ ├── empty_datafile_new_account_id.json
│ ├── empty_datafile_new_project_id.json
│ ├── empty_datafile_new_revision.json
│ ├── empty_traffic_allocation.json
│ ├── feature_exp.json
│ ├── feature_experiments.json
│ ├── feature_flag.json
│ ├── feature_management_experiment_bucketing.json
│ ├── feature_rollout_toggle_off.json
│ ├── feature_rollout_toggle_on.json
│ ├── feature_rollouts.json
│ ├── feature_variables.json
│ ├── forced_variation.json
│ ├── grouped_experiments.json
│ ├── odp
│ │ ├── decide_audience_segments.json
│ │ └── odp_integrated_no_segments.json
│ ├── optimizelyConfig
│ │ ├── optimizely_config_datafile.json
│ │ └── optimizely_config_expected.json
│ ├── optimizely_6372300739_v4.json
│ ├── rollout_bucketing.json
│ ├── simple_datafile.json
│ ├── typed_audience_datafile.json
│ ├── unsupported_datafile.json
│ └── unsupported_version.json
└── TestUtils
│ ├── MockBucketer.swift
│ ├── MockDatafileHandler.swift
│ ├── MockEventDispatcher.swift
│ ├── MockLogger.swift
│ ├── MockUrlSession.swift
│ └── OTUtils.swift
└── pull_request_template.md
/.github/ISSUE_TEMPLATE/ENHANCEMENT.yml:
--------------------------------------------------------------------------------
1 | name: ✨Enhancement
2 | description: Create a new ticket for a Enhancement/Tech-initiative for the benefit of the SDK which would be considered for a minor version update.
3 | title: "[ENHANCEMENT]
"
4 | labels: ["enhancement"]
5 | body:
6 | - type: textarea
7 | id: description
8 | attributes:
9 | label: "Description"
10 | description: Briefly describe the enhancement in a few sentences.
11 | placeholder: Short description...
12 | validations:
13 | required: true
14 | - type: textarea
15 | id: benefits
16 | attributes:
17 | label: "Benefits"
18 | description: How would the enhancement benefit to your product or usage?
19 | placeholder: Benefits...
20 | validations:
21 | required: true
22 | - type: textarea
23 | id: detail
24 | attributes:
25 | label: "Detail"
26 | description: How would you like the enhancement to work? Please provide as much detail as possible
27 | placeholder: Detailed description...
28 | validations:
29 | required: false
30 | - type: textarea
31 | id: examples
32 | attributes:
33 | label: "Examples"
34 | description: Are there any examples of this enhancement in other products/services? If so, please provide links or references.
35 | placeholder: Links/References...
36 | validations:
37 | required: false
38 | - type: textarea
39 | id: risks
40 | attributes:
41 | label: "Risks/Downsides"
42 | description: Do you think this enhancement could have any potential downsides or risks?
43 | placeholder: Risks/Downsides...
44 | validations:
45 | required: false
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.md:
--------------------------------------------------------------------------------
1 |
4 | ## Feedback requesting a new feature can be shared [here.](https://feedback.optimizely.com/)
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 💡Feature Requests
4 | url: https://feedback.optimizely.com/
5 | about: Feedback requesting a new feature can be shared here.
--------------------------------------------------------------------------------
/.github/workflows/integration_tests.yml:
--------------------------------------------------------------------------------
1 | name: Reusable action of Integration tests
2 |
3 | on:
4 | workflow_call:
5 | secrets:
6 | CI_USER_TOKEN:
7 | required: true
8 | jobs:
9 | integration_tests:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | with:
14 | # You should create a personal access token and store it in your repository
15 | token: ${{ secrets.CI_USER_TOKEN }}
16 | repository: 'optimizely/ci-helper-tools'
17 | path: 'home/runner/ci-helper-tools'
18 | ref: 'master'
19 | - name: set SDK Branch if PR
20 | env:
21 | HEAD_REF: ${{ github.head_ref }}
22 | if: ${{ github.event_name == 'pull_request' }}
23 | run: |
24 | echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV
25 | - name: set SDK Branch if not pull request
26 | env:
27 | REF_NAME: ${{ github.ref_name }}
28 | if: ${{ github.event_name != 'pull_request' }}
29 | run: |
30 | echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV
31 | - name: Trigger build
32 | env:
33 | SDK: swift
34 | TESTAPP_TAG: master
35 | BUILD_NUMBER: ${{ github.run_id }}
36 | TESTAPP_BRANCH: master
37 | GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }}
38 | EVENT_TYPE: ${{ github.event_name }}
39 | GITHUB_CONTEXT: ${{ toJson(github) }}
40 | PULL_REQUEST_SLUG: ${{ github.repository }}
41 | UPSTREAM_REPO: ${{ github.repository }}
42 | PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }}
43 | PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
44 | UPSTREAM_SHA: ${{ github.sha }}
45 | EVENT_MESSAGE: ${{ github.event.message }}
46 | HOME: 'home/runner'
47 | run: |
48 | home/runner/ci-helper-tools/trigger-script-with-status-update.sh
49 |
--------------------------------------------------------------------------------
/.github/workflows/lint_markdown.yml:
--------------------------------------------------------------------------------
1 | name: Reusable action of linting markdown files
2 |
3 | on: [workflow_call]
4 |
5 | jobs:
6 | lint_markdown:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | - name: Set up Ruby
11 | uses: ruby/setup-ruby@v1
12 | with:
13 | ruby-version: '2.6'
14 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically
15 | - name: Install gem and Run tests
16 | run: |
17 | cd ../../
18 | gem install awesome_bot
19 | find . -type f -name '*.md' -exec awesome_bot {} \;
20 |
--------------------------------------------------------------------------------
/.github/workflows/source_clear_cron.yml:
--------------------------------------------------------------------------------
1 | name: Source clear
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | schedule:
7 | # Runs "weekly"
8 | - cron: '0 0 * * 0'
9 |
10 | jobs:
11 | source_clear:
12 | runs-on: macos-13
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Source clear scan
16 | env:
17 | SRCCLR_API_TOKEN: ${{ secrets.SRCCLR_API_TOKEN }}
18 | run: |
19 | gem install cocoapods -v '1.9.3'
20 | curl -sSL https://download.sourceclear.com/ci.sh | bash -s - scan
21 |
--------------------------------------------------------------------------------
/.github/workflows/ticket_reference_check.yml:
--------------------------------------------------------------------------------
1 | name: Jira ticket reference check
2 |
3 | on:
4 | pull_request:
5 | types: [opened, edited, reopened, synchronize]
6 |
7 | jobs:
8 |
9 | jira_ticket_reference_check:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Check for Jira ticket reference
14 | uses: optimizely/github-action-ticket-reference-checker-public@master
15 | with:
16 | bodyRegex: 'FSSDK-(?\d+)'
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Finder
2 | .DS_Store
3 |
4 | # Xcode
5 | #
6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
7 |
8 | ## Build generated
9 | build/
10 | DerivedData/
11 |
12 | ## Various settings
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata/
22 |
23 | ## Other
24 | *.moved-aside
25 | *.xcuserstate
26 | *.xcscmblueprint
27 |
28 | ## Obj-C/Swift specific
29 | *.hmap
30 | *.ipa
31 | *.dSYM.zip
32 | *.dSYM
33 |
34 | ### Xcode ###
35 | build
36 | *.xcodeproj/*
37 | !*.xcodeproj/project.pbxproj
38 | !*.xcodeproj/xcshareddata/
39 | !*.xcworkspace/contents.xcworkspacedata
40 |
41 | # CocoaPods
42 | #
43 | # We recommend against adding the Pods directory to your .gitignore. However
44 | # you should judge for yourself, the pros and cons are mentioned at:
45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
46 | Pods/
47 |
48 | # COCOAPODS version at the end of Podfile.lock requires all stick to the same version
49 | # Ignore this and stick pods to fixed versions in Podfile
50 | Podfile.lock
51 |
52 | # Carthage
53 | #
54 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
55 | # Carthage/Checkouts
56 |
57 | Carthage/Build
58 |
59 | # SPM
60 |
61 | .build
62 | .swiftpm
63 | Packages
64 |
65 | # fastlane
66 | #
67 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
68 | # screenshots whenever they are needed.
69 | # For more information about the recommended setup visit:
70 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
71 |
72 | fastlane/report.xml
73 | fastlane/screenshots
74 |
75 | #Code Injection
76 | #
77 | # After new code Injection tools there's a generated folder /iOSInjectionProject
78 | # https://github.com/johnno1962/injectionforxcode
79 |
80 | iOSInjectionProject/
81 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - trailing_whitespace
3 | - force_cast
4 | - empty_count
5 | - todo
6 | - implicit_getter
7 | - private_over_fileprivate
8 | - inclusive_language
9 | opt_in_rules:
10 | - empty_string
11 | excluded:
12 | - Carthage
13 | - Pods
14 | - SwiftLint/Common/3rdPartyLib
15 | - Tests
16 | line_length:
17 | warning: 350
18 | error: 400
19 | ignores_function_declarations: true
20 | ignores_comments: true
21 | ignores_urls: true
22 | function_body_length:
23 | warning: 300
24 | error: 500
25 | function_parameter_count:
26 | warning: 10
27 | error: 10
28 | type_body_length:
29 | warning: 500
30 | error: 500
31 | file_length:
32 | warning: 1000
33 | error: 1500
34 | ignore_comment_only_lines: true
35 | cyclomatic_complexity:
36 | warning: 20
37 | error: 25
38 | type_name:
39 | min_length: 1
40 | identifier_name:
41 | allowed_symbols: "_"
42 | min_length: 1
43 | max_length:
44 | warning: 90
45 | error: 1000
46 | excluded:
47 | - id
48 | large_tuple:
49 | warning: 4
50 | error: 5
51 | reporter: "xcode"
52 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # This is a comment.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # These owners will be the default owners for everything in the repo.
5 | # Unless a later match takes precedence, @global-owner1 and @global-owner2
6 | # will be requested for review when someone opens a pull request.
7 | * @optimizely/fullstack-devs
8 |
9 | # Order is important; the last matching pattern takes the most precedence.
10 | # When someone opens a pull request that only modifies JS files, only @js-owner
11 | # and not the global owner(s) will be requested for a review.
12 | #*.js @js-owner
13 |
14 | # You can also use email addresses if you prefer. They'll be used to look up
15 | # users just like we do for commit author emails.
16 | #docs/* docs@example.com
17 |
--------------------------------------------------------------------------------
/DemoObjCApp/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 |
19 | @interface AppDelegate : UIResponder
20 |
21 | @property (strong, nonatomic) UIWindow *window;
22 |
23 | @end
24 |
25 |
--------------------------------------------------------------------------------
/DemoObjCApp/Customization/CustomLogger.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 | @import Optimizely;
19 |
20 | NS_ASSUME_NONNULL_BEGIN
21 |
22 | @protocol OPTLogger;
23 |
24 | @interface CustomLogger : NSObject
25 | + (enum OptimizelyLogLevel)logLevel;
26 | + (void)setLogLevel:(enum OptimizelyLogLevel)value;
27 | - (nonnull instancetype)init;
28 | - (void)logWithLevel:(enum OptimizelyLogLevel)level message:(NSString *)message;
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/DemoObjCApp/Customization/CustomLogger.m:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import "CustomLogger.h"
18 | @import Optimizely;
19 |
20 | @implementation CustomLogger
21 |
22 | -(instancetype)init {
23 | self = [super init];
24 | if (self != nil) {
25 | //
26 | }
27 |
28 | return self;
29 | }
30 |
31 | - (void)logWithLevel:(enum OptimizelyLogLevel)level message:(NSString * _Nonnull)message {
32 | if (level <= CustomLogger.logLevel) {
33 | NSLog(@"🐱 - [\(level.name)] Kitty - %@", message);
34 | }
35 | }
36 |
37 | static enum OptimizelyLogLevel logLevel = OptimizelyLogLevelInfo;
38 | +(enum OptimizelyLogLevel)logLevel {
39 | return logLevel;
40 | }
41 | +(void)setLogLevel:(enum OptimizelyLogLevel)value {
42 | logLevel = value;
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/DemoObjCApp/DemoObjcApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DemoObjCApp/DemoObjcApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DemoObjCApp/DemoObjciOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 3
21 | LSRequiresIPhoneOS
22 |
23 | NSAppTransportSecurity
24 |
25 | NSAllowsArbitraryLoads
26 |
27 |
28 | UIBackgroundModes
29 |
30 | fetch
31 |
32 | UILaunchStoryboardName
33 | iOSMain
34 | UIMainStoryboardFile
35 | iOSMain
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UISupportedInterfaceOrientations~ipad
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationPortraitUpsideDown
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/DemoObjCApp/DemoObjctvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIBackgroundModes
24 |
25 | fetch
26 |
27 | UIMainStoryboardFile
28 | tvOSMain
29 | UIRequiredDeviceCapabilities
30 |
31 | arm64
32 |
33 | UIUserInterfaceStyle
34 | Automatic
35 |
36 |
37 |
--------------------------------------------------------------------------------
/DemoObjCApp/Samples/SamplesForAPI.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 |
19 | NS_ASSUME_NONNULL_BEGIN
20 |
21 | @class OptimizelyClient;
22 |
23 | @interface SamplesForAPI: NSObject
24 | +(void)checkAPIs:(OptimizelyClient*)optimizely;
25 | +(void)checkOptimizelyConfig:(OptimizelyClient*)optimizely;
26 | +(void)checkOptimizelyUserContext:(OptimizelyClient*)optimizely;
27 | @end
28 |
29 | NS_ASSUME_NONNULL_END
30 |
--------------------------------------------------------------------------------
/DemoObjCApp/VariationViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 |
19 | @class OptimizelyClient;
20 |
21 | @interface VariationViewController : UIViewController
22 | @property(nullable, nonatomic, strong) OptimizelyClient *optimizely;
23 | @property(nonnull, nonatomic, strong) NSString *eventKey;
24 | @property(nonnull, nonatomic, strong) NSString *variationKey;
25 | @property(nonnull, nonatomic, strong) NSString *userId;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/DemoObjCApp/VariationViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import "VariationViewController.h"
18 | @import Optimizely;
19 |
20 | @interface VariationViewController ()
21 | @property (weak, nonatomic) IBOutlet UILabel *variationLetterLabel;
22 | @property (weak, nonatomic) IBOutlet UILabel *variationSubheaderLabel;
23 | @property (weak, nonatomic) IBOutlet UIImageView *variationBackgroundImage;
24 | @end
25 |
26 | @implementation VariationViewController
27 |
28 | - (void)viewDidLoad {
29 | [super viewDidLoad];
30 |
31 | if ([self.variationKey isEqualToString:@"variation_a"]) {
32 | self.variationLetterLabel.text = @"A";
33 | self.variationLetterLabel.textColor = [UIColor blackColor];
34 | self.variationSubheaderLabel.textColor = [UIColor blackColor];
35 | self.variationBackgroundImage.image = [UIImage imageNamed:@"background_variA"];
36 | } else {
37 | self.variationLetterLabel.text = @"B";
38 | self.variationLetterLabel.textColor = [UIColor whiteColor];
39 | self.variationSubheaderLabel.textColor = [UIColor whiteColor];
40 | self.variationBackgroundImage.image = [UIImage imageNamed:@"background_variB-marina"];
41 | }
42 | }
43 |
44 | - (IBAction)unwindToVariationAction:(UIStoryboardSegue *)segue {
45 |
46 | }
47 |
48 | - (IBAction)attemptTrackAndShowSuccessOrFailure:(id)sender {
49 | NSError *error;
50 |
51 | BOOL status = [self.optimizely trackWithEventKey:self.eventKey userId:self.userId attributes:nil eventTags:nil error:&error];
52 |
53 | if (status) {
54 | [self performSegueWithIdentifier:@"ConversionSuccessSegue" sender:self];
55 | } else {
56 | [self performSegueWithIdentifier:@"ConversionFailureSegue" sender:self];
57 | }
58 | }
59 |
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/DemoObjCApp/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 | #import "AppDelegate.h"
19 |
20 | int main(int argc, char * argv[]) {
21 | @autoreleasepool {
22 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DemoSwiftApp/Customization/CustomLogger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomLogger
3 | // DemoSwiftiOS
4 | //
5 | // Created by Jae Kim on 1/11/19.
6 | // Copyright © 2019 Optimizely. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Optimizely
11 |
12 | class CustomLogger: OPTLogger {
13 | public static var logLevel: OptimizelyLogLevel = .info
14 |
15 | required init() {
16 | }
17 |
18 | public func log(level: OptimizelyLogLevel, message: String) {
19 | if level.rawValue <= CustomLogger.logLevel.rawValue {
20 | print("🐱 - [\(level.name)] Kitty - \(message)")
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftiOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 3
21 | LSRequiresIPhoneOS
22 |
23 | NSAppTransportSecurity
24 |
25 | NSAllowsArbitraryLoads
26 |
27 |
28 | UIBackgroundModes
29 |
30 | fetch
31 |
32 | UIMainStoryboardFile
33 | iOSMain
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UISupportedInterfaceOrientations~ipad
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationPortraitUpsideDown
48 | UIInterfaceOrientationLandscapeLeft
49 | UIInterfaceOrientationLandscapeRight
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwifttvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIBackgroundModes
24 |
25 | fetch
26 |
27 | UIMainStoryboardFile
28 | tvOSMain
29 | UIRequiredDeviceCapabilities
30 |
31 | arm64
32 |
33 | UIUserInterfaceStyle
34 | Automatic
35 |
36 |
37 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "role" : "notificationCenter",
6 | "scale" : "2x",
7 | "size" : "24x24",
8 | "subtype" : "38mm"
9 | },
10 | {
11 | "idiom" : "watch",
12 | "role" : "notificationCenter",
13 | "scale" : "2x",
14 | "size" : "27.5x27.5",
15 | "subtype" : "42mm"
16 | },
17 | {
18 | "idiom" : "watch",
19 | "role" : "companionSettings",
20 | "scale" : "2x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "watch",
25 | "role" : "companionSettings",
26 | "scale" : "3x",
27 | "size" : "29x29"
28 | },
29 | {
30 | "idiom" : "watch",
31 | "role" : "appLauncher",
32 | "scale" : "2x",
33 | "size" : "40x40",
34 | "subtype" : "38mm"
35 | },
36 | {
37 | "idiom" : "watch",
38 | "role" : "appLauncher",
39 | "scale" : "2x",
40 | "size" : "44x44",
41 | "subtype" : "40mm"
42 | },
43 | {
44 | "idiom" : "watch",
45 | "role" : "appLauncher",
46 | "scale" : "2x",
47 | "size" : "50x50",
48 | "subtype" : "44mm"
49 | },
50 | {
51 | "idiom" : "watch",
52 | "role" : "quickLook",
53 | "scale" : "2x",
54 | "size" : "86x86",
55 | "subtype" : "38mm"
56 | },
57 | {
58 | "idiom" : "watch",
59 | "role" : "quickLook",
60 | "scale" : "2x",
61 | "size" : "98x98",
62 | "subtype" : "42mm"
63 | },
64 | {
65 | "idiom" : "watch",
66 | "role" : "quickLook",
67 | "scale" : "2x",
68 | "size" : "108x108",
69 | "subtype" : "44mm"
70 | },
71 | {
72 | "idiom" : "watch-marketing",
73 | "scale" : "1x",
74 | "size" : "1024x1024"
75 | }
76 | ],
77 | "info" : {
78 | "author" : "xcode",
79 | "version" : 1
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Base.lproj/Interface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | DemoSwiftwatchOS WatchKit App
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | UISupportedInterfaceOrientations
24 |
25 | UIInterfaceOrientationPortrait
26 | UIInterfaceOrientationPortraitUpsideDown
27 |
28 | WKWatchKitApp
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit Extension/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit Extension/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Optimizely
18 | import WatchKit
19 |
20 | class ExtensionDelegate: NSObject, WKExtensionDelegate {
21 | let logLevel = OptimizelyLogLevel.debug
22 | var optimizely: OptimizelyClient!
23 |
24 | let sdkKey = "FCnSegiEkRry9rhVMroit4"
25 | let featureKey = "decide_demo"
26 | let eventKey = "sample_conversion"
27 | let userId = String(Int.random(in: 0..<100000))
28 | let attributes: [String: Any] = ["location": "NY",
29 | "bool_attr": false,
30 | "semanticVersioning": "1.2"]
31 |
32 | func applicationDidFinishLaunching() {
33 | optimizely = OptimizelyClient(sdkKey: sdkKey, defaultLogLevel: logLevel)
34 |
35 | optimizely.start { result in
36 | switch result {
37 | case .failure(let error):
38 | print("Optimizely SDK initiliazation failed: \(error)")
39 | case .success:
40 | print("Optimizely SDK initialized successfully!")
41 |
42 | let user = self.optimizely.createUserContext(userId: self.userId, attributes: self.attributes)
43 | let decision = user.decide(key: self.featureKey, options: [.includeReasons])
44 | print("[DECISION] \(decision)")
45 | try? user.trackEvent(eventKey: self.eventKey)
46 | @unknown default:
47 | print("Optimizely SDK initiliazation failed with unknown result")
48 | }
49 | }
50 | }
51 |
52 | func applicationDidBecomeActive() {
53 | WatchBackgroundNotifier.applicationDidBecomeActive()
54 | }
55 |
56 | func applicationDidEnterBackground() {
57 | WatchBackgroundNotifier.applicationDidEnterBackground()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | DemoSwiftwatchOS WatchKit Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | WKAppBundleIdentifier
28 | com.optimizely.DemoSwiftwatchOS.watchkitapp
29 |
30 | NSExtensionPointIdentifier
31 | com.apple.watchkit
32 |
33 | WKExtensionDelegateClassName
34 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
35 | WKWatchOnly
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/DemoSwiftApp/DemoSwiftwatchOS WatchKit Extension/InterfaceController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import WatchKit
18 | import Foundation
19 |
20 |
21 | class InterfaceController: WKInterfaceController {
22 |
23 | override func awake(withContext context: Any?) {
24 | // Configure interface objects here.
25 | }
26 |
27 | override func willActivate() {
28 | // This method is called when watch view controller is about to be visible to user
29 | }
30 |
31 | override func didDeactivate() {
32 | // This method is called when watch view controller is no longer visible
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-1024.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-72.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-20@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-settings.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-settings@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-spotlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-spotlight.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-spotlight@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon-iPad-spotlight@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_1024x768.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_1024x768.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_1536x2048.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_1536x2048.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_2048x1536.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_2048x1536.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_640x1136.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_640x1136.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_640x960.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_640x960.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_768x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image1_768x1024.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1024x748.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1024x748.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1024x768.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1024x768.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1242x2208.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1242x2208.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1536x2008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1536x2008.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1536x2048.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_1536x2048.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2048x1496.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2048x1496.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2048x1536.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2048x1536.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2208x1242.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_2208x1242.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_320x480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_320x480.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_640x1136.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_640x1136.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_640x960.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_640x960.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_750x1334.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_750x1334.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_768x1004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_768x1004.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_768x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/LaunchImage.launchimage/image_768x1024.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_confirmation@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_confirmation@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_confirmation@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_error@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_error@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_error@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_error.imageset/background_error@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_variA@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_variA@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_variA@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variA.imageset/background_variA@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_variB-marina@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_variB-marina@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_variB-marina@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "logo@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "logo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "logo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwiftiOS/Assets.xcassets/logo.imageset/logo@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-large_back.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/icon-large_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/icon-large_back.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-large_front.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/icon-large_front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/icon-large_front.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-large_middle.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/icon-large_middle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/icon-large_middle.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-small_back.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "filename" : "icon-small_back@2x.png",
11 | "scale" : "2x"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/icon-small_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/icon-small_back.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/icon-small_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/icon-small_back@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-small_front.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "filename" : "icon-small_front@2x.png",
11 | "scale" : "2x"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/icon-small_front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/icon-small_front.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/icon-small_front@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/icon-small_front@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-small_middle.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "filename" : "icon-small_middle@2x.png",
11 | "scale" : "2x"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/icon-small_middle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/icon-small_middle.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/icon-small_middle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/icon-small_middle@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "size" : "1280x768",
5 | "idiom" : "tv",
6 | "filename" : "App Icon - Large.imagestack",
7 | "role" : "primary-app-icon"
8 | },
9 | {
10 | "size" : "400x240",
11 | "idiom" : "tv",
12 | "filename" : "App Icon - Small.imagestack",
13 | "role" : "primary-app-icon"
14 | },
15 | {
16 | "size" : "2320x720",
17 | "idiom" : "tv",
18 | "filename" : "Top Shelf Image Wide.imageset",
19 | "role" : "top-shelf-image-wide"
20 | },
21 | {
22 | "size" : "1920x720",
23 | "idiom" : "tv",
24 | "filename" : "Top Shelf Image.imageset",
25 | "role" : "top-shelf-image"
26 | }
27 | ],
28 | "info" : {
29 | "version" : 1,
30 | "author" : "xcode"
31 | }
32 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-top_shelf_wide.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "filename" : "icon-top_shelf_wide@2x.png",
11 | "scale" : "2x"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/icon-top_shelf_wide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/icon-top_shelf_wide.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/icon-top_shelf_wide@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/icon-top_shelf_wide@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "filename" : "icon-top_shelf.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "tv",
10 | "filename" : "icon-top_shelf@2x.png",
11 | "scale" : "2x"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/icon-top_shelf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/icon-top_shelf.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/icon-top_shelf@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/icon-top_shelf@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "landscape",
5 | "idiom" : "tv",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "11.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "landscape",
12 | "idiom" : "tv",
13 | "filename" : "LaunchImage.png",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "9.0",
16 | "scale" : "1x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/LaunchImage.launchimage/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/LaunchImage.launchimage/LaunchImage.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_confirmation@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_confirmation@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_confirmation@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_confirmation.imageset/background_confirmation@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_error@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_error@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_error@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_error.imageset/background_error@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_variA@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_variA@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_variA@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variA.imageset/background_variA@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "background_variB-marina@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "background_variB-marina@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "background_variB-marina@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/background_variB-marina.imageset/background_variB-marina@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "logo@1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "logo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "logo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@1x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@2x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/DemoSwifttvOS/Assets.xcassets/logo.imageset/logo@3x.png
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/Resources/ProximaNova-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/Resources/ProximaNova-Regular.otf
--------------------------------------------------------------------------------
/DemoSwiftApp/SharedResources/Resources/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/optimizely/swift-sdk/993701ce28eaf9784a20f30f692d3a4e5e83cb44/DemoSwiftApp/SharedResources/Resources/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "OptimizelySwiftSDK"
3 | s.module_name = "Optimizely"
4 | s.version = "5.1.1"
5 | s.summary = "Optimizely experiment framework for iOS/tvOS/watchOS"
6 | s.homepage = "https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs"
7 | s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
8 | s.author = { "Optimizely" => "support@optimizely.com" }
9 | s.ios.deployment_target = "10.0"
10 | s.tvos.deployment_target = "10.0"
11 | s.osx.deployment_target = "10.14"
12 | s.watchos.deployment_target = "3.0"
13 | s.source = {
14 | :git => "https://github.com/optimizely/swift-sdk.git",
15 | :tag => "v"+s.version.to_s
16 | }
17 | s.source_files = "Sources/**/*.swift"
18 | s.resource_bundles = { 'OptimizelySwiftSDK' => ['Sources/Supporting Files/PrivacyInfo.xcprivacy'] }
19 | s.swift_version = ["5.0", "5.1"]
20 | s.framework = "Foundation"
21 | s.requires_arc = true
22 | s.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => "OPTIMIZELY_SDK_VERSION=@\\\"#{s.version}\\\"" }
23 | end
24 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6E636B8B2236C91F00AF3CEF.xcbaseline/2564B2A6-3658-41F8-8220-6CC2F6018D25.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6E636B8B2236C91F00AF3CEF.xcbaseline/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | runDestinationsByUUID
6 |
7 | 2564B2A6-3658-41F8-8220-6CC2F6018D25
8 |
9 | localComputer
10 |
11 | busSpeedInMHz
12 | 100
13 | cpuCount
14 | 1
15 | cpuKind
16 | Intel Core i7
17 | cpuSpeedInMHz
18 | 2500
19 | logicalCPUCoresPerPackage
20 | 8
21 | modelCode
22 | MacBookPro11,4
23 | physicalCPUCoresPerPackage
24 | 4
25 | platformIdentifier
26 | com.apple.platform.macosx
27 |
28 | targetArchitecture
29 | x86_64
30 | targetDevice
31 |
32 | modelCode
33 | iPhone11,8
34 | platformIdentifier
35 | com.apple.platform.iphonesimulator
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6EBAEB7321E3FEF900D13AA9.xcbaseline/97A8F182-0DA1-4499-B20E-185EB633EA3E.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | classNames
6 |
7 | OptimizelyManagerTests
8 |
9 | testPerformanceBasicExperiment()
10 |
11 | com.apple.XCTPerformanceMetric_WallClockTime
12 |
13 | baselineAverage
14 | 0.0014232
15 | baselineIntegrationDisplayName
16 | Local Baseline
17 |
18 |
19 | testPerformanceInitialize()
20 |
21 | com.apple.XCTPerformanceMetric_WallClockTime
22 |
23 | baselineAverage
24 | 0.0037978
25 | baselineIntegrationDisplayName
26 | Local Baseline
27 |
28 |
29 | testPerformanceTypedAudience()
30 |
31 | com.apple.XCTPerformanceMetric_WallClockTime
32 |
33 | baselineAverage
34 | 0.0043147
35 | baselineIntegrationDisplayName
36 | Local Baseline
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6EBAEB7321E3FEF900D13AA9.xcbaseline/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | runDestinationsByUUID
6 |
7 | 97A8F182-0DA1-4499-B20E-185EB633EA3E
8 |
9 | localComputer
10 |
11 | busSpeedInMHz
12 | 100
13 | cpuCount
14 | 1
15 | cpuKind
16 | Intel Core i7
17 | cpuSpeedInMHz
18 | 2500
19 | logicalCPUCoresPerPackage
20 | 8
21 | modelCode
22 | MacBookPro11,4
23 | physicalCPUCoresPerPackage
24 | 4
25 | platformIdentifier
26 | com.apple.platform.macosx
27 |
28 | targetArchitecture
29 | x86_64
30 | targetDevice
31 |
32 | modelCode
33 | iPhone11,8
34 | platformIdentifier
35 | com.apple.platform.iphonesimulator
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcworkspace/xcshareddata/IDETemplateMacros.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | FILEHEADER
6 |
7 | // Copyright 2022, Optimizely, Inc. and contributors
8 | //
9 | // Licensed under the Apache License, Version 2.0 (the "License");
10 | // you may not use this file except in compliance with the License.
11 | // You may obtain a copy of the License at
12 | //
13 | // http://www.apache.org/licenses/LICENSE-2.0
14 | //
15 | // Unless required by applicable law or agreed to in writing, software
16 | // distributed under the License is distributed on an "AS IS" BASIS,
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | // See the License for the specific language governing permissions and
19 | // limitations under the License.
20 | //
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OptimizelySwiftSDK.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The Swift tools version declares the version of the PackageDescription library,
3 | // the minimum version of the Swift tools and Swift language compatibility version to process the manifest,
4 | // and the minimum version of the Swift tools that are needed to use the Swift package.
5 |
6 | import PackageDescription
7 |
8 | let package = Package(
9 | name: "Optimizely",
10 | platforms: [
11 | .iOS(.v10),
12 | .tvOS(.v10),
13 | .macOS(.v10_14),
14 | .watchOS(.v3)
15 | ],
16 | products: [
17 | .library(name: "Optimizely",
18 | targets: ["Optimizely"])
19 | ],
20 | targets: [
21 | .target(
22 | name: "Optimizely",
23 | path: "Sources",
24 | resources: [.copy("Supporting Files/PrivacyInfo.xcprivacy")]
25 | )
26 | ],
27 | swiftLanguageVersions: [.v5]
28 | )
29 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | workspace 'OptimizelySwiftSDK.xcworkspace'
2 |
3 | def analytics_pods
4 | # pod 'Amplitude-iOS'
5 | # pod 'Google/Analytics'
6 | # pod 'Localytics'
7 | # pod 'Mixpanel-swift', '2.5.7'
8 | end
9 |
10 | def linter_pods
11 | # ignore all warnings from all dependencies
12 | inhibit_all_warnings!
13 | pod 'SwiftLint', '0.43.1'
14 | end
15 |
16 | def common_test_pods
17 | pod 'OCMock', '3.7.1'
18 | end
19 |
20 | target 'DemoSwiftiOS' do
21 | project 'DemoSwiftApp/DemoSwiftApp.xcodeproj/'
22 | platform :ios, '10.0'
23 | use_frameworks!
24 | analytics_pods
25 | linter_pods
26 | #pod 'OptimizelySwiftSDK','3.0.0'
27 | end
28 |
29 | target 'DemoSwifttvOS' do
30 | project 'DemoSwiftApp/DemoSwiftApp.xcodeproj/'
31 | platform :tvos, '10.0'
32 | use_frameworks!
33 | linter_pods
34 | #pod 'OptimizelySwiftSDK','3.0.0'
35 | end
36 |
37 | target 'DemoObjciOS' do
38 | project 'DemoObjcApp/DemoObjcApp.xcodeproj/'
39 | platform :ios, '10.0'
40 | use_frameworks!
41 | analytics_pods
42 | #pod 'OptimizelySwiftSDK','3.0.0'
43 | end
44 |
45 | target 'DemoObjctvOS' do
46 | project 'DemoObjcApp/DemoObjcApp.xcodeproj/'
47 | platform :tvos, '10.0'
48 | use_frameworks!
49 | #pod 'OptimizelySwiftSDK','3.0.0'
50 | end
51 |
52 | target 'OptimizelyTests-Common-iOS' do
53 | project 'OptimizelySwiftSDK.xcodeproj/'
54 | platform :ios, '10.0'
55 | common_test_pods
56 | end
57 |
58 | target 'OptimizelyTests-Common-tvOS' do
59 | project 'OptimizelySwiftSDK.xcodeproj/'
60 | platform :tvos, '10.0'
61 | common_test_pods
62 | end
63 |
64 | # Disable Code Coverage for Pods projects
65 | post_install do |installer_representation|
66 | installer_representation.pods_project.targets.each do |target|
67 | target.build_configurations.each do |config|
68 | config.build_settings['CLANG_ENABLE_CODE_COVERAGE'] = 'NO'
69 | # fix OCMock old iOS8 target warning
70 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '10.0'
71 | end
72 | end
73 | end
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Scripts/build_all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ################################################################
3 | # buildall.sh
4 | ################################################################
5 | set -e
6 |
7 | cleanup() {
8 | rm -f "${tempfiles[@]}"
9 | }
10 | trap cleanup 0
11 |
12 | error() {
13 | local lineno="$1"
14 | local message="$2"
15 | local code="${3:-1}"
16 | if [[ -n "${message}" ]] ; then
17 | echo "Error on line ${lineno}: ${message}; status ${code}"
18 | else
19 | echo "Error on line ${lineno}; status ${code}"
20 | fi
21 | exit "${code}"
22 | }
23 | trap 'error ${LINENO}' ERR
24 |
25 | main() {
26 | action="build"
27 |
28 | if [[ "$#" == "1" ]]; then
29 | # TODO: This isn't the best, but you can supply "clean" to our command.
30 | action="$1"
31 | fi;
32 |
33 | xcodebuild -workspace OptimizelySwiftSDK.xcworkspace -scheme OptimizelySwiftSDK-iOS -configuration Release "${action}"
34 | xcodebuild -workspace OptimizelySwiftSDK.xcworkspace -scheme OptimizelySwiftSDK-tvOS -configuration Release "${action}"
35 | xcodebuild -workspace OptimizelySwiftSDK.xcworkspace -scheme OptimizelySwiftSDK-macOS -configuration Release "${action}"
36 | xcodebuild -workspace OptimizelySwiftSDK.xcworkspace -scheme OptimizelySwiftSDK-watchOS -configuration Release "${action}"
37 | }
38 |
39 | main
40 |
--------------------------------------------------------------------------------
/Scripts/change_header/header.template:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright 2020, Optimizely, Inc. and contributors *
3 | * *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); *
5 | * you may not use this file except in compliance with the License. *
6 | * You may obtain a copy of the License at *
7 | * *
8 | * http://www.apache.org/licenses/LICENSE-2.0 *
9 | * *
10 | * Unless required by applicable law or agreed to in writing, software *
11 | * distributed under the License is distributed on an "AS IS" BASIS, *
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 | * See the License for the specific language governing permissions and *
14 | * limitations under the License. *
15 | ***************************************************************************/
16 |
--------------------------------------------------------------------------------
/Scripts/change_header/remove_header.awk:
--------------------------------------------------------------------------------
1 | # This script removes ANSI C file header comments
2 | BEGIN { start = 0; incomment = 0;}
3 |
4 | {
5 | if (start == 0)
6 | {
7 | if (incomment == 0)
8 | {
9 | # C++ single line comment
10 | if (/^\/\//)
11 | {
12 | # print "single line"
13 | }
14 | # single line comment
15 | else if (/^\/\*[^\/]*\*\/$/)
16 | {
17 | # print "single line"
18 | }
19 | # multi line comment
20 | else if (/^\/\*/)
21 | {
22 | #print "start comment"
23 | # start multi line comment
24 | incomment = 1
25 | }
26 | else
27 | {
28 | # first line that is not a comment, start normal output
29 | print $0;
30 | start = 1;
31 | }
32 | }
33 | else
34 | {
35 | # search for comment end
36 | if (/\*\//)
37 | {
38 | #print "end comment"
39 | incomment = 0;
40 | }
41 | }
42 | }
43 | else
44 | {
45 | # print the complete line for the rest of the file
46 | print $0
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Scripts/change_header/replace_header.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SOURCE_DIR=`dirname $0`
3 | if [ $# != 1 ]; then
4 | echo "Usage: replace_header.sh "
5 | exit 1
6 | fi
7 |
8 | cat $SOURCE_DIR/header.template > $SOURCE_DIR/tmp
9 | cat "$1" | awk -f $SOURCE_DIR/remove_header.awk >> $SOURCE_DIR/tmp
10 | mv $SOURCE_DIR/tmp "$1"
11 |
12 |
--------------------------------------------------------------------------------
/Scripts/change_header/replace_headers_folder.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | if [ $# != 1 ]; then
3 | echo "Usage: replace_headers_folder.sh "
4 | exit 1
5 | fi
6 |
7 | SCRIPT_DIR=`dirname $0`
8 | ROOT_DIR="${PWD}/$1"
9 |
10 | # do no break spaces in file names
11 | IFS=$'\n'
12 |
13 | pushd $SCRIPT_DIR > /dev/null
14 |
15 | for f in $(find $ROOT_DIR -name '*.swift' -or -name '*.h' -or -name '*.m')
16 | do
17 | if [[ "$f" == *"Pods/"* ]] ; then
18 | continue
19 | fi
20 |
21 | echo "replacing header for: $f"
22 | replace_header.sh "$f"
23 | done
24 |
25 | popd > /dev/null
26 |
--------------------------------------------------------------------------------
/Scripts/prepare_coveralls_report.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # prepare_coveralls_report.sh
4 | #
5 | # Usage:
6 | # $ ./prepare_coveralls_report.sh
7 | #
8 |
9 | # [coveralls]
10 | # - exclude coverage for Test codes by setting OptimizelySwiftSDK-iOS scheme > Test > Options > Gather coverage for selected targets
11 | mkdir xccov2lcov && cd xccov2lcov && git init && git fetch --depth=1 https://github.com/trax-retail/xccov2lcov.git && git checkout FETCH_HEAD
12 | xcrun xccov view --report --json ../$COVERAGE_DIR/Logs/Test/*.xcresult > coverage.json
13 | swift run xccov2lcov coverage.json > lcov.info
14 | cd ..
15 |
--------------------------------------------------------------------------------
/Scripts/prepare_simulator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | set -eou pipefail
3 |
4 | # expects the following environment variables defined
5 | # PLATFORM (eg. iOS Simulator)
6 | # OS (eg. 12.0)
7 | # NAME (eg. iPad Air)
8 | # OS_TYPE (eg. iOS)
9 | # SIMULATOR_XCODE_VERSION (Which Xcode's simulator to use)
10 | # Since github actions only provides limit simulators with each xcode, we need to link simulators from other versions of xcode to be used by current xcode.
11 | # We must use old simulators with current xcode since older xcode versions do not support swift 5 which is required by Swift SDK.
12 | # More about XCode and its compatible simulators can be found here: https://github.com/actions/virtual-environments/blob/main/images/macos/macos-10.15-Readme.md
13 | # https://github.com/actions/virtual-environments/issues/551
14 |
15 | # Older than Xcode 12 (12.4?) has different paths
16 | MAJOR_SIMULATOR_XCODE_VERSION=$(echo $SIMULATOR_XCODE_VERSION | cut -d. -f1)
17 | if [ "$MAJOR_SIMULATOR_XCODE_VERSION" -lt 12 ]; then
18 | os_folder="iPhoneOS"
19 | os="${OS/./-}"
20 | name="${NAME//[ ()]/-}"
21 |
22 | sudo mkdir -p /Library/Developer/CoreSimulator/Profiles/Runtimes
23 |
24 | # Check if device is Apple tv, update os_folder for linking purposes
25 | if [[ "$NAME" = "Apple TV"* ]]
26 | then
27 | name="${name}-1080p"
28 | os_folder="AppleTVOS"
29 | fi
30 |
31 | # update os_folder as per xcode version
32 | if [ "$SIMULATOR_XCODE_VERSION" == 10.3 ]
33 | then
34 | os_folder="${os_folder}.platform/Developer/Library"
35 | else
36 | os_folder="${os_folder}.platform/Library/Developer"
37 | fi
38 |
39 | # Link and create simulators from older xcode versions which are not part of the current xcode version
40 | sudo ln -s /Applications/Xcode_$SIMULATOR_XCODE_VERSION.app/Contents/Developer/Platforms/$os_folder/CoreSimulator/Profiles/Runtimes/$OS_TYPE.simruntime /Library/Developer/CoreSimulator/Profiles/Runtimes/$OS_TYPE\ $OS.simruntime
41 | xcrun simctl create "custom-device" "com.apple.CoreSimulator.SimDeviceType.$name" "com.apple.CoreSimulator.SimRuntime.$OS_TYPE-$os"
42 | CUSTOM_SIMULATOR="$(instruments -s devices | grep -m 1 'custom-device' | awk -F'[][]' '{print $2}')"
43 | else
44 | echo ".devices.\"com.apple.CoreSimulator.SimRuntime.${PLATFORM/ Simulator/}-${OS/./-}\"" > /tmp/jq_file
45 | CUSTOM_SIMULATOR=$( xcrun simctl list --json devices | jq -f /tmp/jq_file | jq -r '.[] | select(.name==env.NAME) | .udid' )
46 | fi
47 | xcrun simctl boot $CUSTOM_SIMULATOR && sleep 30
48 | xcrun simctl list | grep Booted
49 |
--------------------------------------------------------------------------------
/Scripts/run_unit_tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # run xcode unit tests
4 | #
5 | # Usage:
6 | # $ ./run_unit_tests.sh
7 | #
8 |
9 | # unit tests for PR only
10 | if [[ "$BRANCH" == "master" ]]
11 | then
12 | xcodebuild test -derivedDataPath $COVERAGE_DIR -workspace OptimizelySwiftSDK.xcworkspace -scheme $SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK -destination "platform=$PLATFORM,OS=$OS,name=$NAME" ONLY_ACTIVE_ARCH=YES | tee buildoutput | xcpretty && test ${PIPESTATUS[0]} -eq 0
13 | fi
14 |
--------------------------------------------------------------------------------
/Scripts/runtimeVersion.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | TEST_VAR=":blush:"
3 | oldName="$1"
4 | newName="$2"
5 | swift_code() {
6 | cat< DefaultLogger.logLevel {
37 | return
38 | }
39 |
40 | clog(level: level, message: message)
41 | }
42 |
43 | func clog(level: OptimizelyLogLevel, message: String) {
44 | var osLogType: OSLogType
45 |
46 | switch level {
47 | case .error: osLogType = .error
48 | case .info: osLogType = .info
49 | case .debug: osLogType = .debug
50 | default: osLogType = .default
51 | }
52 |
53 | os_log("[%{public}@] %{public}@", log: .optimizely, type: osLogType, level.name, message)
54 | }
55 |
56 | // test support
57 |
58 | static func setLogLevel(_ level: OptimizelyLogLevel) {
59 | _logLevel = level
60 | }
61 | }
62 |
63 | extension OSLog {
64 | static let optimizely = OSLog(subsystem: "com.optimizely.swift-sdk", category: "OPTIMIZELY")
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/Customization/Protocols/OPTEventDispatcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | public typealias DispatchCompletionHandler = (OptimizelyResult) -> Void
20 |
21 | /// The OPTEventDispatcher dispatches events to the Optimizely backend used in results.
22 | public protocol OPTEventDispatcher {
23 |
24 | /// Dispatch event to Optimizely backend for results measurement.
25 | ///
26 | /// - Parameters:
27 | /// - event: EventForDispatch object which contains the url to send to and the body.
28 | /// - completionHandler: Called when the event has been sent or if an error occured.
29 | /// This may not be called in the case where the dispatcher is doing batch events. It is up to the implementor of the protocol.
30 | func dispatchEvent(event: EventForDispatch, completionHandler: DispatchCompletionHandler?)
31 |
32 | /// Attempts to flush the event queue if there are any events to process.
33 | func flushEvents()
34 |
35 | /// flush events in queue synchrnonous (optional for testing support)
36 | func close()
37 | }
38 |
39 | public extension OPTEventDispatcher {
40 | // override this for testing support only
41 | func close() {}
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Customization/Protocols/OPTUserProfileService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct UserProfileKeys {
20 | static let kBucketMap = "experiment_bucket_map"
21 | static let kVariationId = "variation_id"
22 | static let kUserId = "user_id"
23 | }
24 |
25 | @objc public protocol OPTUserProfileService {
26 |
27 | typealias UPProfile = [String: Any] // {"experiment_bucket_map", "user_id"}
28 | typealias UPBucketMap = [String: UPExperimentMap]
29 | typealias UPExperimentMap = [String: String]
30 |
31 | init()
32 |
33 | /**
34 | Returns a user entity corresponding to the user ID.
35 | - Parameter userId: The user id to get the user entity of.
36 | - Returns: A dictionary of the user profile details.
37 | **/
38 | func lookup(userId: String) -> UPProfile?
39 |
40 | /**
41 | Saves the user profile.
42 | - Parameter userProfile: The user profile.
43 | **/
44 | func save(userProfile: UPProfile)
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/Data Model/Attribute.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Attribute: Codable, Equatable, OptimizelyAttribute {
20 | var id: String
21 | var key: String
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Data Model/Audience/ConditionLeaf.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | enum ConditionLeaf: Codable, Equatable {
20 | case audienceId(String)
21 | case attribute(UserAttribute)
22 |
23 | init(from decoder: Decoder) throws {
24 | let container = try decoder.singleValueContainer()
25 |
26 | if let value = try? container.decode(String.self) {
27 | self = .audienceId(value)
28 | return
29 | } else if let value = try? container.decode(UserAttribute.self) {
30 | self = .attribute(value)
31 | return
32 | }
33 |
34 | throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "Failed to decode ConditionLeaf"))
35 | }
36 |
37 | func encode(to encoder: Encoder) throws {
38 | var container = encoder.singleValueContainer()
39 |
40 | switch self {
41 | case .audienceId(let id):
42 | try container.encode(id)
43 | case .attribute(let userAttribute):
44 | try container.encode(userAttribute)
45 | }
46 | }
47 |
48 | func evaluate(project: ProjectProtocol?, user: OptimizelyUserContext) throws -> Bool {
49 | switch self {
50 | case .audienceId(let id):
51 | guard let project = project else {
52 | throw OptimizelyError.conditionCannotBeEvaluated("audienceId: \(id)")
53 | }
54 |
55 | return try project.evaluateAudience(audienceId: id, user: user)
56 | case .attribute(let userAttribute):
57 | return try userAttribute.evaluate(user: user)
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/Data Model/Cmab.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Cmab: Codable, Equatable {
20 | var trafficAllocation: Int
21 | var attributeIds: [String]
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Data Model/DispatchEvents/EventForDispatch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | @objcMembers public class EventForDispatch: NSObject, Codable {
20 | public static var eventEndpoint = "https://logx.optimizely.com/v1/events"
21 |
22 | public let url: URL
23 | public let body: Data
24 |
25 | public init(url: URL? = nil, body: Data) {
26 | self.url = url ?? URL(string: EventForDispatch.eventEndpoint)!
27 | self.body = body
28 | }
29 |
30 | // override NSObject Equatable ('==' overriding not working for NSObject)
31 | override public func isEqual(_ object: Any?) -> Bool {
32 | guard let object = object as? EventForDispatch else { return false }
33 | return url == object.url && body == object.body
34 | }
35 | }
36 |
37 | extension EventForDispatch {
38 | override public var description: String {
39 | return "[url] \(url) (" + (String(data: body, encoding: .utf8) ?? "UNKNOWN") + ")"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/Data Model/Event.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Event: Codable, Equatable, OptimizelyEvent {
20 | var id: String
21 | var key: String
22 | var experimentIds: [String]
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/Data Model/FeatureFlag.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct FeatureFlag: Codable, Equatable, OptimizelyFeature {
20 | static func == (lhs: FeatureFlag, rhs: FeatureFlag) -> Bool {
21 | return lhs.id == rhs.id
22 | }
23 |
24 | var id: String
25 | var key: String
26 | var experimentIds: [String]
27 | var rolloutId: String
28 | var variables: [FeatureVariable]
29 |
30 | enum CodingKeys: String, CodingKey {
31 | case id
32 | case key
33 | case experimentIds
34 | case rolloutId
35 | case variables
36 | }
37 |
38 | // MARK: - OptimizelyConfig
39 |
40 | var experimentsMap: [String: OptimizelyExperiment] = [:]
41 | var variablesMap: [String: OptimizelyVariable] = [:]
42 | var experimentRules: [OptimizelyExperiment] = []
43 | var deliveryRules: [OptimizelyExperiment] = []
44 | }
45 |
46 | // MARK: - Utils
47 |
48 | extension FeatureFlag {
49 | func getVariable(key: String) -> FeatureVariable? {
50 | return variables.filter { $0.key == key }.first
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/Data Model/FeatureVariable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019-2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct FeatureVariable: Codable, Equatable {
20 | var id: String
21 | var key: String
22 | var type: String
23 | var subType: String?
24 | // datafile schema requires this, but test has "null" value case. keep optional for FSC
25 | var defaultValue: String?
26 |
27 | enum CodingKeys: String, CodingKey {
28 | case id
29 | case key
30 | case type
31 | case subType
32 | case defaultValue
33 | }
34 |
35 | init(id: String, key: String, type: String, subType: String?, defaultValue: String?) {
36 | self.id = id
37 | self.key = key
38 | self.type = type
39 | self.subType = subType
40 | self.defaultValue = defaultValue
41 | overrideTypeIfJSON()
42 | }
43 |
44 | init(from decoder: Decoder) throws {
45 | let container = try decoder.container(keyedBy: CodingKeys.self)
46 | id = try container.decode(String.self, forKey: .id)
47 | key = try container.decode(String.self, forKey: .key)
48 | type = try container.decode(String.self, forKey: .type)
49 | subType = try container.decodeIfPresent(String.self, forKey: .subType)
50 | defaultValue = try container.decodeIfPresent(String.self, forKey: .defaultValue)
51 | overrideTypeIfJSON()
52 | }
53 |
54 | mutating func overrideTypeIfJSON() {
55 | if type == Constants.VariableValueType.string.rawValue && subType == Constants.VariableValueType.json.rawValue {
56 | type = Constants.VariableValueType.json.rawValue
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/Data Model/Group.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019-2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Group: Codable, Equatable {
20 | enum Policy: String, Codable {
21 | case random
22 | case overlapping
23 | }
24 |
25 | var id: String
26 | var policy: Policy
27 | var trafficAllocation: [TrafficAllocation]
28 | var experiments: [Experiment]
29 | }
30 |
31 | // MARK: - Utils
32 |
33 | extension Group {
34 |
35 | func getExperiment(id: String) -> Experiment? {
36 | return experiments.filter { $0.id == id }.first
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/Data Model/Integration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Integration: Codable, Equatable {
20 | var key: String
21 | var host: String?
22 | var publicKey: String?
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/Data Model/Rollout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | import Foundation
17 |
18 | struct Rollout: Codable, Equatable {
19 | var id: String
20 | var experiments: [Experiment]
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Data Model/TrafficAllocation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct TrafficAllocation: Codable, Equatable {
20 | var entityId: String // can be empty string "" to indicate not-allocated range
21 | var endOfRange: Int
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Data Model/Variable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Variable: Codable, Equatable {
20 | var id: String
21 | var value: String
22 |
23 | enum CodingKeys: String, CodingKey {
24 | case id
25 | case value
26 | }
27 |
28 | // for OptimizelyConfig only
29 |
30 | var key: String = ""
31 | var type: String = "string"
32 | }
33 |
34 | // MARK: - OptimizelyConfig
35 |
36 | extension Variable: OptimizelyVariable {
37 | init(id: String, value: String, key: String? = nil, type: String? = nil) {
38 | self.id = id
39 | self.value = value
40 | if let key = key {
41 | self.key = key
42 | }
43 | if let type = type {
44 | self.type = type
45 | }
46 | }
47 |
48 | init(featureVariable: FeatureVariable) {
49 | self.id = featureVariable.id
50 | self.key = featureVariable.key
51 | self.type = featureVariable.type
52 | self.value = featureVariable.defaultValue ?? ""
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Sources/Data Model/Variation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | struct Variation: Codable, OptimizelyVariation {
20 | var id: String
21 | var key: String
22 | var featureEnabled: Bool?
23 | var variables: [Variable]?
24 |
25 | enum CodingKeys: String, CodingKey {
26 | case id, key, featureEnabled, variables
27 | }
28 |
29 | // MARK: - OptimizelyConfig
30 |
31 | var variablesMap: [String: OptimizelyVariable] = [:]
32 | }
33 |
34 | extension Variation: Equatable {
35 | static func == (lhs: Variation, rhs: Variation) -> Bool {
36 | return lhs.id == rhs.id &&
37 | lhs.key == rhs.key &&
38 | lhs.featureEnabled == rhs.featureEnabled &&
39 | lhs.variables == rhs.variables
40 | }
41 | }
42 |
43 | // MARK: - Utils
44 |
45 | extension Variation {
46 | func getVariable(id: String) -> Variable? {
47 | return variables?.filter { $0.id == id }.first
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/Extensions/Array+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | // MARK: - logical ops on eval array
20 |
21 | typealias ThrowableCondition = () throws -> Bool
22 | typealias ThrowableConditionList = [ThrowableCondition]
23 |
24 | extension Array where Element == ThrowableCondition {
25 |
26 | // returns true only when all items are true and no-error
27 | func and() throws -> Bool {
28 | guard self.count > 0 else {
29 | throw OptimizelyError.conditionInvalidFormat("AND with empty items")
30 | }
31 |
32 | for eval in self {
33 | if try eval() == false {
34 | return false
35 | }
36 | }
37 |
38 | return true
39 | }
40 |
41 | // return try if any item is true (even with other error items)
42 | func or() throws -> Bool {
43 | var foundError: OptimizelyError?
44 |
45 | for eval in self {
46 | do {
47 | if try eval() { return true }
48 | } catch let error as OptimizelyError {
49 | foundError = error
50 | }
51 | }
52 |
53 | if let error = foundError {
54 | throw error
55 | }
56 | return false
57 | }
58 |
59 | // evalute the 1st item only
60 | func not() throws -> Bool {
61 | guard let eval = self.first else {
62 | throw OptimizelyError.conditionInvalidFormat("NOT with empty items")
63 | }
64 |
65 | let result = try eval()
66 | return !result
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/Extensions/DataStoreQueueStackImpl+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | extension DataStoreQueueStack {
20 | func getFirstItem() -> T? {
21 | return getFirstItems(count: 1)?.first
22 | }
23 | func getLastItem() -> T? {
24 | return getLastItems(count: 1)?.first
25 | }
26 | func removeFirstItem() -> T? {
27 | return removeFirstItems(count: 1)?.first
28 | }
29 | func removeLastItem() -> T? {
30 | return removeLastItems(count: 1)?.first
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/Implementation/DecisionReasons.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | protocol ReasonProtocol {
20 | var reason: String { get }
21 | }
22 |
23 | class DecisionReasons {
24 | var errors: [ReasonProtocol]
25 | var infos: [ReasonProtocol]?
26 |
27 | init(includeInfos: Bool = true) {
28 | errors = []
29 | if includeInfos {
30 | infos = []
31 | }
32 | }
33 |
34 | convenience init(options: [OptimizelyDecideOption]?) {
35 | // include infos if options is not provided (default)
36 | self.init(includeInfos: options?.contains(.includeReasons) ?? true)
37 | }
38 |
39 | func addError(_ error: ReasonProtocol) {
40 | errors.append(error)
41 | }
42 |
43 | func addInfo(_ info: ReasonProtocol) {
44 | infos?.append(info)
45 | }
46 |
47 | func merge(_ reasons: DecisionReasons) {
48 | errors.append(contentsOf: reasons.errors)
49 | infos?.append(contentsOf: reasons.infos ?? [])
50 | }
51 |
52 | func toReport() -> [String] {
53 | return (errors + (infos ?? [])).map { $0.reason }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Implementation/DecisionResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019-2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class DecisionResponse {
20 | var result: T?
21 | var reasons: DecisionReasons
22 |
23 | init(result: T?, reasons: DecisionReasons) {
24 | self.result = result
25 | self.reasons = reasons
26 | }
27 |
28 | static func responseNoReasons(result: T?) -> DecisionResponse {
29 | return DecisionResponse(result: result, reasons: DecisionReasons(includeInfos: false))
30 | }
31 |
32 | static func nilNoReasons() -> DecisionResponse {
33 | return DecisionResponse(result: nil, reasons: DecisionReasons(includeInfos: false))
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/ODP/OptimizelySegmentOption.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | /// Options controlling audience segments.
20 | @objc public enum OptimizelySegmentOption: Int {
21 | // ignore cache (save/lookup)
22 | case ignoreCache
23 | // reset cache
24 | case resetCache
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/Optimizely+Decide/OptimizelyDecideOption.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | /// Options controlling flag decisions.
20 | @objc public enum OptimizelyDecideOption: Int {
21 | /// disable decision event tracking.
22 | case disableDecisionEvent
23 |
24 | /// return decisions only for flags which are enabled (decideAll only).
25 | case enabledFlagsOnly
26 |
27 | /// skip user profile service for decision.
28 | case ignoreUserProfileService
29 |
30 | /// include info and debug messages in the decision reasons.
31 | case includeReasons
32 |
33 | /// exclude variable values from the decision result.
34 | case excludeVariables
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/Optimizely/OptimizelyJSON+ObjC.swift:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright 2020-2021, Optimizely, Inc. and contributors *
3 | * *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); *
5 | * you may not use this file except in compliance with the License. *
6 | * You may obtain a copy of the License at *
7 | * *
8 | * http://www.apache.org/licenses/LICENSE-2.0 *
9 | * *
10 | * Unless required by applicable law or agreed to in writing, software *
11 | * distributed under the License is distributed on an "AS IS" BASIS, *
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 | * See the License for the specific language governing permissions and *
14 | * limitations under the License. *
15 | ***************************************************************************/
16 | import Foundation
17 |
18 | extension OptimizelyJSON {
19 |
20 | @available(swift, obsoleted: 1.0)
21 | @objc(initWithPayload:)
22 | convenience init?(p: String) {
23 | self.init(payload: p)
24 | }
25 |
26 | @available(swift, obsoleted: 1.0)
27 | @objc(initWithMap:)
28 | convenience init?(m: [String: Any]) {
29 | self.init(map: m)
30 | }
31 |
32 | /// - Returns: true when one or more variables are included.
33 | @available(swift, obsoleted: 1.0)
34 | @objc(isEmpty)
35 | public func objcIsEmpty() -> Bool {
36 | return self.isEmpty
37 | }
38 |
39 | @available(swift, obsoleted: 1.0)
40 | @objc(toString)
41 | /// - Returns: The string representation of json
42 | public func objcToString() -> String? {
43 | return self.toString()
44 | }
45 |
46 | @available(swift, obsoleted: 1.0)
47 | @objc(toMap)
48 | /// - Returns: The json dictionary
49 | public func objcToMap() -> [String: Any] {
50 | return self.toMap()
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/Optimizely/OptimizelyLogLevel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | @objc public enum OptimizelyLogLevel: Int {
20 |
21 | /// If the filter level is set to OptimizelyLogLevelOff, all log messages will be suppressed.
22 | case off = 0
23 | /// Any error that is not causing a crash of the application: unknown experiment referenced.
24 | case error = 1
25 | /// Anything that can potentially cause problems: method will be deprecated.
26 | case warning = 2
27 | /// Useful information: Lifecycle events, successfully activated experiment, parsed datafile.
28 | case info = 3
29 | /// Information diagnostically helpful: sending events, assigning buckets.
30 | case debug = 4
31 | /// Used for the most granular logging: method flows, variable values.
32 | case verbose = 5
33 |
34 | // NOTE: this property is not converted for ObjC APIs (separate map should be defined for ObjC-client customization)
35 | public var name: String {
36 | switch self {
37 | case .off: return "OFF"
38 | case .error: return "ERROR"
39 | case .warning: return "WARNING"
40 | case .info: return "INFO"
41 | case .debug: return "DEBUG"
42 | case .verbose: return "VERBOSE"
43 | }
44 | }
45 | }
46 |
47 | extension OptimizelyLogLevel: Comparable {
48 | public static func < (lhs: OptimizelyLogLevel, rhs: OptimizelyLogLevel) -> Bool {
49 | return lhs.rawValue < rhs.rawValue
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/Optimizely/OptimizelyResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | public enum OptimizelyResult {
20 | case success(Value)
21 | case failure(OptimizelyError)
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Protocols/BackgroundingCallbacks.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | #if os(watchOS)
20 | import WatchKit
21 | #elseif os(macOS)
22 | import Cocoa
23 | #else
24 | import UIKit
25 | #endif
26 |
27 | @objc protocol BackgroundingCallbacks {
28 | func applicationDidEnterBackground()
29 | func applicationDidBecomeActive()
30 | }
31 |
32 | private extension NSNotification.Name {
33 | #if os(macOS)
34 | static let didEnterBackground = NSApplication.didResignActiveNotification
35 | static let didBecomeActive = NSApplication.didBecomeActiveNotification
36 | #elseif os(iOS) || os(tvOS)
37 | static let didEnterBackground = UIApplication.didEnterBackgroundNotification
38 | static let didBecomeActive = UIApplication.didBecomeActiveNotification
39 | #elseif os(watchOS)
40 | static let didEnterBackground = WatchBackgroundNotifier.watchAppDidEnterBackgroundNotification
41 | static let didBecomeActive = WatchBackgroundNotifier.watchAppDidBecomeActiveNotification
42 | #endif
43 | }
44 |
45 | extension BackgroundingCallbacks {
46 | func subscribe() {
47 | // swift4.2+
48 | NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: .didEnterBackground, object: nil)
49 | NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: .didBecomeActive, object: nil)
50 | }
51 |
52 | func unsubscribe() {
53 | // swift4.2+
54 | NotificationCenter.default.removeObserver(self, name: .didEnterBackground, object: nil)
55 | NotificationCenter.default.removeObserver(self, name: .didBecomeActive, object: nil)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/Protocols/DataStoreQueueStack.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | /// A protocol that can be used as a queue or a stack with a backing datastore. All items stored in a datastore queue stack must be of the same type.
20 | public protocol DataStoreQueueStack {
21 | var count: Int { get }
22 | /// save item of type T
23 | /// - Parameter item: item to save. It is both append and push.
24 | func save(item: T)
25 | /// getFirstItem - queue peek
26 | /// - Returns: value of the first item added or nil.
27 | func getFirstItems(count: Int) -> [T]?
28 | /// getLastItem - stack peek.
29 | /// - Returns: value of the last item added or nil.
30 | func getLastItems(count: Int) -> [T]?
31 | /// removeFirstItem - queue get. It removes and returns the first item in the queue if it exists.
32 | /// - Returns: value of the first item in the queue.
33 | func removeFirstItems(count: Int) -> [T]?
34 | /// removeLastItem - stack pop. It removes and returns the last item item added if it exists.
35 | /// - Returns: value of the last item pushed onto the stack.
36 | func removeLastItems(count: Int) -> [T]?
37 |
38 | associatedtype T
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/Protocols/OPTDataStore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | /// Simple DataStore using key value. This abstracts away the datastore layer. The datastore should take into account synchronization.
20 | public protocol OPTDataStore {
21 |
22 | /// getItem - get an item by key.
23 | /// - Parameter forKey: key to lookup datastore value.
24 | /// - Returns: the value saved or nil
25 | func getItem(forKey: String) -> Any?
26 | /// saveItem - save the item to the datastore.
27 | /// - Parameter forKey: key to save value
28 | /// - Parameter value: value to save.
29 | func saveItem(forKey: String, value: Any)
30 | /// removeItem - remove the item to the datastore.
31 | /// - Parameter forKey: key to save value
32 | func removeItem(forKey: String)
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | $(CURRENT_PROJECT_VERSION)
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sources/Supporting Files/Optimizely.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | @import Foundation;
18 |
19 | //! Project version number for Optimizely.
20 | FOUNDATION_EXPORT double OptimizelyVersionNumber;
21 |
22 | //! Project version string for Optimizely.
23 | FOUNDATION_EXPORT const unsigned char OptimizelyVersionString[];
24 |
25 | // In this header, you should import all the public headers of your framework using statements like #import
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Sources/Supporting Files/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyCollectedDataTypes
6 |
7 |
8 | NSPrivacyCollectedDataType
9 | NSPrivacyCollectedDataTypeProductInteraction
10 | NSPrivacyCollectedDataTypeLinked
11 |
12 | NSPrivacyCollectedDataTypeTracking
13 |
14 | NSPrivacyCollectedDataTypePurposes
15 |
16 | NSPrivacyCollectedDataTypePurposeAnalytics
17 |
18 |
19 |
20 | NSPrivacyAccessedAPITypes
21 |
22 |
23 | NSPrivacyAccessedAPIType
24 | NSPrivacyAccessedAPICategoryUserDefaults
25 | NSPrivacyAccessedAPITypeReasons
26 |
27 | CA92.1
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Sources/Utils/AtomicDictionary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class AtomicDictionary: AtomicWrapper {
20 | private var _property: [K: V]
21 |
22 | var property: [K: V] {
23 | get {
24 | return getAtomic {
25 | _property
26 | }!
27 | }
28 | set {
29 | performAtomic {
30 | self._property = newValue
31 | }
32 | }
33 | }
34 |
35 | init(_ property: [K: V] = [:]) {
36 | self._property = property
37 | }
38 |
39 | subscript(key: K) -> V? {
40 | get {
41 | return getAtomic {
42 | _property[key]
43 | }
44 | }
45 | set {
46 | performAtomic {
47 | self._property[key] = newValue
48 | }
49 | }
50 | }
51 |
52 | var count: Int {
53 | return getAtomic {
54 | _property.count
55 | }!
56 | }
57 |
58 | func removeAll() {
59 | performAtomic {
60 | self._property.removeAll()
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Sources/Utils/AtomicProperty.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class AtomicProperty {
20 | private var _property: T?
21 | var property: T? {
22 | get {
23 | var retVal: T?
24 | lock.sync {
25 | retVal = _property
26 | }
27 | return retVal
28 | }
29 | set {
30 | lock.async(flags: DispatchWorkItemFlags.barrier) {
31 | self._property = newValue
32 | }
33 | }
34 | }
35 | private let lock: DispatchQueue
36 |
37 | init(property: T?, lock: DispatchQueue? = nil) {
38 | self._property = property
39 | self.lock = lock ?? {
40 | var name = "AtomicProperty" + String(Int.random(in: 0...100000))
41 | let className = String(describing: T.self)
42 | name += className
43 | return DispatchQueue(label: name, attributes: .concurrent)
44 | }()
45 | }
46 |
47 | convenience init() {
48 | self.init(property: nil, lock: nil)
49 | }
50 |
51 | // perform an atomic operation on the atomic property
52 | // the operation will not run if the property is nil.
53 | func performAtomic(atomicOperation: (_ prop:inout T) -> Void) {
54 | lock.sync(flags: DispatchWorkItemFlags.barrier) {
55 | if var prop = _property {
56 | atomicOperation(&prop)
57 | _property = prop
58 | }
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/Utils/Notifications.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021-2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | extension Notification.Name {
20 | static let willSendOptimizelyEvents = Notification.Name("willSendOptimizelyEvents")
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Utils/SDKVersion.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, 2023 Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | /// Do not edit this field.
18 | /// - It is auto updated (Scripts/updated_version.sh) to reflect the current version
19 | /// - Do not put underscores in the name (Swiftlint can modify unexpectedly)
20 | let OPTIMIZELYSDKVERSION = "5.1.1"
21 |
--------------------------------------------------------------------------------
/Sources/Utils/ThreadSafeLogger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class ThreadSafeLogger {
20 |
21 | // thread-safe lazy logger (after HandlerRegisterService ready)
22 | // - "lazy var" is not thread-safe
23 | // - call this thread-safe version when required to be lazy-init. logger should be initialized before (for customiziation) or at the same time with OptimizelyClient (so HandlerRegisterService is not ready yet).
24 | // - [DefaultDatafileHandler, DefaultEventDispatcher, DefaultDecisionService, DefaultBucketer]
25 |
26 | private var instance: OPTLogger?
27 | private let lock = DispatchQueue(label: "logger")
28 |
29 | var logger: OPTLogger {
30 | var result: OPTLogger?
31 | lock.sync {
32 | if instance == nil {
33 | instance = OPTLoggerFactory.getLogger()
34 | }
35 | result = instance
36 | }
37 | return result!
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/watchOS/WatchBackgroundNotifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #if os(watchOS)
18 | import Foundation
19 |
20 | /// watchOS adds support for background notifications in watchOS 7.0 with `WKExtension.applicationDidEnterBackgroundNotification`
21 | /// and related notifications. But since this SDK is backwards compatible with watchOS 3.0, these notifications are not available. Instead, the user
22 | /// should implement the appropriate background methods on their Extension Delegate and call the `WatchBackgroundNotifier` from those
23 | /// methods.
24 | public final class WatchBackgroundNotifier {
25 | private init() {}
26 |
27 | public static func applicationDidBecomeActive() {
28 | NotificationCenter.default.post(name: Self.watchAppDidBecomeActiveNotification, object: self)
29 | }
30 |
31 | public static func applicationDidEnterBackground() {
32 | NotificationCenter.default.post(name: Self.watchAppDidEnterBackgroundNotification, object: self)
33 | }
34 | }
35 |
36 | public extension WatchBackgroundNotifier {
37 | static let watchAppDidBecomeActiveNotification = NSNotification.Name(
38 | rawValue: "com.optimizely.watchAppWillEnterForegroundNotification"
39 | )
40 |
41 | static let watchAppDidEnterBackgroundNotification = NSNotification.Name(
42 | rawValue: "com.optimizely.watchAppDidEnterBackgroundNotification"
43 | )
44 | }
45 | #endif
46 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-APIs/OptimizelyClientTests_Group.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 | import XCTest
19 |
20 | class OptimizelyClientTests_Group: XCTestCase {
21 |
22 | let kUserId = "q456789"
23 |
24 | var datafile: Data?
25 | var optimizely: OptimizelyClient?
26 | var eventDispatcher: MockEventDispatcher?
27 |
28 | // MARK: - Attribute Value Range
29 |
30 | func testFeatureEnabledMutextGroup() {
31 | let optimizely = OTUtils.createOptimizely(datafileName: "grouped_experiments",
32 | clearUserProfileService: true)!
33 |
34 | let featureEnabled = optimizely.isFeatureEnabled(featureKey: "mutex_group_feature", userId: kUserId)
35 | XCTAssertTrue(featureEnabled)
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-APIs/OptimizelyErrorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class OptimizelyErrorTests: XCTestCase {
20 |
21 | func testReason() {
22 | let error = OptimizelyError.sdkNotReady
23 | XCTAssert(error.reason.contains("Optimizely SDK not configured properly yet"))
24 | }
25 |
26 | func testErrorDescription() {
27 | let error = OptimizelyError.sdkNotReady
28 | XCTAssert(error.reason == error.errorDescription)
29 | }
30 |
31 | func testDescription() {
32 | let error = OptimizelyError.sdkNotReady
33 | XCTAssert(error.description.contains("[Optimizely][Error]"))
34 | XCTAssert(error.description.contains(error.reason))
35 | }
36 |
37 | func testLocalizedDescription() {
38 | let error = OptimizelyError.sdkNotReady
39 | XCTAssert(error.description == error.localizedDescription)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-Common/DefaultLoggerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class DefaultLoggerTests: XCTestCase {
20 |
21 | func testLoggerDefaultsToInfoLogLevel() {
22 | let logLevel = DefaultLogger.logLevel
23 | XCTAssertEqual(logLevel, .info)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-Common/OptimizelyErrorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class OptimizelyErrorTests: XCTestCase {
20 |
21 | func testErrorDescription() {
22 | let description = "10111"
23 | let error = OptimizelyError.eventDispatchFailed(description)
24 | XCTAssertTrue(error.localizedDescription.contains(description))
25 | XCTAssertTrue(error.errorDescription!.contains(description))
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-DataModel/AttributeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | // MARK: - Sample Data
20 |
21 | class AttributeTests: XCTestCase {
22 | static var sampleData = ["id": "553339214", "key": "house"]
23 | }
24 |
25 | // MARK: - Decode
26 |
27 | extension AttributeTests {
28 |
29 | func testDecodeSuccessWithJSONValid() {
30 | let data = ["id": "553339214", "key": "house"]
31 | let model: Attribute = try! OTUtils.model(from: data)
32 |
33 | XCTAssert(model.id == "553339214")
34 | XCTAssert(model.key == "house")
35 | }
36 |
37 | func testDecodeSuccessWithExtraFields() {
38 | let data = ["id": "553339214", "key": "house", "extra": "123"]
39 | let model: Attribute = try! OTUtils.model(from: data)
40 |
41 | XCTAssert(model.id == "553339214")
42 | XCTAssert(model.key == "house")
43 | }
44 |
45 | func testDecodeFailWithMissingKey() {
46 | let data = ["id": "553339214"]
47 | let model: Attribute? = try? OTUtils.model(from: data)
48 | XCTAssertNil(model)
49 | }
50 |
51 | func testDecodeFailWithMissingId() {
52 | let data = ["key": "house"]
53 | let model: Attribute? = try? OTUtils.model(from: data)
54 | XCTAssertNil(model)
55 | }
56 |
57 | func testDecodeFailWithJSONEmpty() {
58 | let data = [String: String]()
59 | let model: Attribute? = try? OTUtils.model(from: data)
60 | XCTAssertNil(model)
61 | }
62 |
63 | // MARK: - Encode
64 |
65 | func testEncodeJSON() {
66 | let modelGiven = Attribute(id: "553339214", key: "house")
67 | XCTAssert(OTUtils.isEqualWithEncodeThenDecode(modelGiven))
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-DataModel/CmabTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2022, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class CmabTests: XCTestCase {
20 | static var sampleData: [String: Any] = ["trafficAllocation": 10000, "attributeIds": ["id_1", "id_2"]]
21 |
22 | func testDecodeSuccessValidJson() {
23 | let data = Self.sampleData
24 | let cmab: Cmab = try! OTUtils.model(from: data)
25 | XCTAssertEqual(cmab.attributeIds, ["id_1", "id_2"])
26 | XCTAssertEqual(cmab.trafficAllocation, 10000)
27 | }
28 |
29 | func testDecodeSuccessEmptyIds() {
30 | var data = Self.sampleData
31 | data["attributeIds"] = []
32 | let cmab: Cmab = try! OTUtils.model(from: data)
33 | XCTAssertEqual(cmab.attributeIds, [])
34 | XCTAssertEqual(cmab.trafficAllocation, 10000)
35 | }
36 |
37 | func testDecodFailedWithoutTrafficAllocation() {
38 | let data = ["attributeIds": ["id_1", "id_2"]]
39 | let cmab: Cmab? = try? OTUtils.model(from: data)
40 | XCTAssertNil(cmab)
41 | }
42 |
43 | func testDecodFailedWithoutAttributeIds() {
44 | let data = ["trafficAllocation": 10000]
45 | let cmab: Cmab? = try? OTUtils.model(from: data)
46 | XCTAssertNil(cmab)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-DataModel/ConditionLeafTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class ConditionLeafTests: XCTestCase {
20 |
21 | func testDecodeSample_UserAttribute() {
22 | let userAttribute: UserAttribute = try! OTUtils.model(from: UserAttributeTests.sampleData)
23 | let model: ConditionLeaf = try! OTUtils.model(from: UserAttributeTests.sampleData)
24 |
25 | XCTAssert(model == ConditionLeaf.attribute(userAttribute))
26 | }
27 |
28 | func testDecodeSample_AudienceId() {
29 | let audienceId = "12345"
30 | // JSON does not support raw string, so wrap in array for decode
31 | let model: [ConditionLeaf] = try! OTUtils.model(from: [audienceId])
32 |
33 | XCTAssert(model[0] == ConditionLeaf.audienceId(audienceId))
34 | }
35 |
36 | func testDecodeSample_Invalid() {
37 |
38 | var tmpError: Error?
39 | do {
40 | let invalidData = 100
41 | // JSON does not support raw string, so wrap in array for decode
42 | let _: [ConditionLeaf] = try OTUtils.model(from: [invalidData])
43 | } catch {
44 | tmpError = error
45 | }
46 | XCTAssertTrue(tmpError != nil)
47 | XCTAssertTrue(tmpError is DecodingError)
48 | }
49 |
50 | func testEvaluate_InvalidProject() {
51 | let audienceId = "12345"
52 | // JSON does not support raw string, so wrap in array for decode
53 | let model: [ConditionLeaf] = try! OTUtils.model(from: [audienceId])
54 | var tmpError: Error?
55 | do {
56 | let _ = try model[0].evaluate(project: nil, user: OTUtils.user(attributes: ["country": "us"]))
57 | } catch {
58 | tmpError = error
59 | }
60 | XCTAssertTrue(tmpError != nil)
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-DataModel/RolloutTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019, 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | // MARK: - Sample Data
20 |
21 | class RolloutTests: XCTestCase {
22 | static var sampleData: [String: Any] = ["id": "11111",
23 | "experiments": [ExperimentTests.sampleData]]
24 | }
25 |
26 | // MARK: - Decode
27 |
28 | extension RolloutTests {
29 |
30 | func testDecodeSuccessWithJSONValid() {
31 | let data: [String: Any] = RolloutTests.sampleData
32 |
33 | let model: Rollout = try! OTUtils.model(from: data)
34 |
35 | XCTAssert(model.id == "11111")
36 | XCTAssert(model.experiments == [try! OTUtils.model(from: ExperimentTests.sampleData)])
37 | }
38 |
39 | func testDecodeFailWithMissingId() {
40 | var data: [String: Any] = RolloutTests.sampleData
41 | data["id"] = nil
42 |
43 | let model: Rollout? = try? OTUtils.model(from: data)
44 | XCTAssertNil(model)
45 | }
46 |
47 | func testDecodeFailWithMissingExperiments() {
48 | var data: [String: Any] = RolloutTests.sampleData
49 | data["experiments"] = nil
50 |
51 | let model: Rollout? = try? OTUtils.model(from: data)
52 | XCTAssertNil(model)
53 | }
54 |
55 | }
56 |
57 | // MARK: - Encode
58 |
59 | extension RolloutTests {
60 |
61 | func testEncodeJSON() {
62 | let data: [String: Any] = RolloutTests.sampleData
63 | let modelGiven: Rollout = try! OTUtils.model(from: data)
64 |
65 | XCTAssert(OTUtils.isEqualWithEncodeThenDecode(modelGiven))
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/Tests/OptimizelyTests-MultiClients/ProjectConfigTests_MultiClients.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import XCTest
18 |
19 | class ProjectConfigTests_MultiClients: XCTestCase {
20 | var config: ProjectConfig!
21 |
22 | override func setUpWithError() throws {
23 | config = ProjectConfig()
24 | }
25 |
26 | func testConcurrentAccess() {
27 | let numThreads = 10
28 | let numEventsPerThread = 100
29 |
30 | let result = OTUtils.runConcurrent(count: numThreads) { thIdx in
31 | for idx in 0.. Int {
29 | return mockBucketValue
30 | }
31 | }
32 |
33 | // MARK: - Mock Decision Service
34 |
35 | class MockDecisionService: DefaultDecisionService {
36 | init(bucketer: OPTBucketer, userProfileService: OPTUserProfileService = DefaultUserProfileService()) {
37 | super.init(userProfileService: userProfileService, bucketer: bucketer)
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/Tests/TestUtils/MockDatafileHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class MockDatafileHandler: DefaultDatafileHandler {
20 | var statusCode: Int = 0
21 | var withError: Bool = false
22 | var localResponseData: String?
23 | var settingsMap: [String: (Int, Bool)]?
24 |
25 | init(statusCode: Int = 0, withError: Bool = false, localResponseData: String? = nil) {
26 | self.statusCode = statusCode
27 | self.withError = withError
28 | self.localResponseData = localResponseData
29 | }
30 |
31 | init(settingsMap: [String: (Int, Bool)]) {
32 | self.settingsMap = settingsMap
33 | }
34 |
35 | public required init() {}
36 |
37 | override func getSession(resourceTimeoutInterval: Double?) -> URLSession {
38 | if let settingsMap = settingsMap {
39 | return MockUrlSession(handler: self, settingsMap: settingsMap)
40 | } else {
41 | return MockUrlSession(handler: self, statusCode: statusCode, withError: withError, localResponseData: localResponseData)
42 | }
43 | }
44 |
45 | // MARK: - helpers
46 |
47 | func getDatafile(sdkKey: String) -> String {
48 | return localResponseData ?? "datafile-for-\(sdkKey)"
49 | }
50 |
51 | func getLastModified(sdkKey: String) -> String {
52 | return "date-for-\(sdkKey)"
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Tests/TestUtils/MockEventDispatcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class MockEventDispatcher: OPTEventDispatcher {
20 | public var events = [EventForDispatch]()
21 | public var totalEventsFlushed: Int
22 |
23 | init() {
24 | totalEventsFlushed = 0
25 | }
26 |
27 | func dispatchEvent(event: EventForDispatch, completionHandler: DispatchCompletionHandler?) {
28 | events.append(event)
29 | }
30 |
31 | func flushEvents() {
32 | totalEventsFlushed += events.count
33 | events.removeAll()
34 | }
35 | }
36 |
37 | class MockDefaultEventDispatcher: DefaultEventDispatcher {
38 | var withError: Bool
39 |
40 | init(withError: Bool) {
41 | self.withError = withError
42 | super.init()
43 | }
44 |
45 | override func getSession() -> URLSession {
46 | return MockUrlSession(withError: withError)
47 | }
48 | }
49 |
50 |
51 | class DumpEventDispatcher: DefaultEventDispatcher {
52 | public var totalEventsSent: Int
53 |
54 | init(dataStoreName: String = "OPTEventQueue", timerInterval: TimeInterval = DefaultValues.timeInterval) {
55 | totalEventsSent = 0
56 | super.init(dataStoreName: dataStoreName, timerInterval: timerInterval)
57 | }
58 |
59 | override func sendEvent(event: EventForDispatch, completionHandler: @escaping DispatchCompletionHandler) {
60 | if let decodedEvent = try? JSONDecoder().decode(BatchEvent.self, from: event.body) {
61 | totalEventsSent += decodedEvent.visitors.count
62 | }
63 |
64 | completionHandler(.success(Data()))
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/Tests/TestUtils/MockLogger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021, Optimizely, Inc. and contributors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | class MockLogger: OPTLogger {
20 | static var logFound = false
21 | static var expectedLog = ""
22 | private static var _logLevel: OptimizelyLogLevel?
23 |
24 | public static var logLevel: OptimizelyLogLevel {
25 | get {
26 | return _logLevel ?? .info
27 | }
28 | set (newLevel){
29 | if _logLevel == nil {
30 | _logLevel = newLevel
31 | }
32 | }
33 | }
34 |
35 | required public init() {
36 | MockLogger.logLevel = .info
37 | }
38 |
39 | open func log(level: OptimizelyLogLevel, message: String) {
40 | if ("[Optimizely][Error] " + message) == MockLogger.expectedLog {
41 | MockLogger.logFound = true
42 | }
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Summary
2 | - The "what"; a concise description of each logical change
3 | - Another change
4 |
5 | The "why", or other context.
6 |
7 | ## Test plan
8 |
9 | ## Issues
10 | - "THING-1234" or "Fixes #123"
11 |
--------------------------------------------------------------------------------