├── .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 | <!-- 2 | Thanks for filing in issue! Are you requesting a new feature? If so, please share your feedback with us on the following link. 3 | --> 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-(?<ticketNumber>\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 <UIKit/UIKit.h> 18 | 19 | @interface AppDelegate : UIResponder <UIApplicationDelegate> 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 <Foundation/Foundation.h> 18 | @import Optimizely; 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | @protocol OPTLogger; 23 | 24 | @interface CustomLogger : NSObject <OPTLogger> 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <Workspace 3 | version = "1.0"> 4 | <FileRef 5 | location = "self:DemoObjcApp.xcodeproj"> 6 | </FileRef> 7 | </Workspace> 8 | -------------------------------------------------------------------------------- /DemoObjCApp/DemoObjcApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>IDEDidComputeMac32BitWarning</key> 6 | <true/> 7 | </dict> 8 | </plist> 9 | -------------------------------------------------------------------------------- /DemoObjCApp/DemoObjciOS/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>en</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>APPL</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>1.0</string> 19 | <key>CFBundleVersion</key> 20 | <string>3</string> 21 | <key>LSRequiresIPhoneOS</key> 22 | <true/> 23 | <key>NSAppTransportSecurity</key> 24 | <dict> 25 | <key>NSAllowsArbitraryLoads</key> 26 | <true/> 27 | </dict> 28 | <key>UIBackgroundModes</key> 29 | <array> 30 | <string>fetch</string> 31 | </array> 32 | <key>UILaunchStoryboardName</key> 33 | <string>iOSMain</string> 34 | <key>UIMainStoryboardFile</key> 35 | <string>iOSMain</string> 36 | <key>UIRequiredDeviceCapabilities</key> 37 | <array> 38 | <string>armv7</string> 39 | </array> 40 | <key>UISupportedInterfaceOrientations</key> 41 | <array> 42 | <string>UIInterfaceOrientationPortrait</string> 43 | <string>UIInterfaceOrientationLandscapeLeft</string> 44 | <string>UIInterfaceOrientationLandscapeRight</string> 45 | </array> 46 | <key>UISupportedInterfaceOrientations~ipad</key> 47 | <array> 48 | <string>UIInterfaceOrientationPortrait</string> 49 | <string>UIInterfaceOrientationPortraitUpsideDown</string> 50 | <string>UIInterfaceOrientationLandscapeLeft</string> 51 | <string>UIInterfaceOrientationLandscapeRight</string> 52 | </array> 53 | </dict> 54 | </plist> 55 | -------------------------------------------------------------------------------- /DemoObjCApp/DemoObjctvOS/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>en</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>APPL</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>1.0</string> 19 | <key>CFBundleVersion</key> 20 | <string>1</string> 21 | <key>LSRequiresIPhoneOS</key> 22 | <true/> 23 | <key>UIBackgroundModes</key> 24 | <array> 25 | <string>fetch</string> 26 | </array> 27 | <key>UIMainStoryboardFile</key> 28 | <string>tvOSMain</string> 29 | <key>UIRequiredDeviceCapabilities</key> 30 | <array> 31 | <string>arm64</string> 32 | </array> 33 | <key>UIUserInterfaceStyle</key> 34 | <string>Automatic</string> 35 | </dict> 36 | </plist> 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 <Foundation/Foundation.h> 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 <UIKit/UIKit.h> 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 <UIKit/UIKit.h> 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <Workspace 3 | version = "1.0"> 4 | <FileRef 5 | location = "self:"> 6 | </FileRef> 7 | </Workspace> 8 | -------------------------------------------------------------------------------- /DemoSwiftApp/DemoSwiftApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>IDEDidComputeMac32BitWarning</key> 6 | <true/> 7 | </dict> 8 | </plist> 9 | -------------------------------------------------------------------------------- /DemoSwiftApp/DemoSwiftiOS/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>en</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>APPL</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>1.0</string> 19 | <key>CFBundleVersion</key> 20 | <string>3</string> 21 | <key>LSRequiresIPhoneOS</key> 22 | <true/> 23 | <key>NSAppTransportSecurity</key> 24 | <dict> 25 | <key>NSAllowsArbitraryLoads</key> 26 | <true/> 27 | </dict> 28 | <key>UIBackgroundModes</key> 29 | <array> 30 | <string>fetch</string> 31 | </array> 32 | <key>UIMainStoryboardFile</key> 33 | <string>iOSMain</string> 34 | <key>UIRequiredDeviceCapabilities</key> 35 | <array> 36 | <string>armv7</string> 37 | </array> 38 | <key>UISupportedInterfaceOrientations</key> 39 | <array> 40 | <string>UIInterfaceOrientationPortrait</string> 41 | <string>UIInterfaceOrientationLandscapeLeft</string> 42 | <string>UIInterfaceOrientationLandscapeRight</string> 43 | </array> 44 | <key>UISupportedInterfaceOrientations~ipad</key> 45 | <array> 46 | <string>UIInterfaceOrientationPortrait</string> 47 | <string>UIInterfaceOrientationPortraitUpsideDown</string> 48 | <string>UIInterfaceOrientationLandscapeLeft</string> 49 | <string>UIInterfaceOrientationLandscapeRight</string> 50 | </array> 51 | </dict> 52 | </plist> 53 | -------------------------------------------------------------------------------- /DemoSwiftApp/DemoSwifttvOS/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>en</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>APPL</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>1.0</string> 19 | <key>CFBundleVersion</key> 20 | <string>1</string> 21 | <key>LSRequiresIPhoneOS</key> 22 | <true/> 23 | <key>UIBackgroundModes</key> 24 | <array> 25 | <string>fetch</string> 26 | </array> 27 | <key>UIMainStoryboardFile</key> 28 | <string>tvOSMain</string> 29 | <key>UIRequiredDeviceCapabilities</key> 30 | <array> 31 | <string>arm64</string> 32 | </array> 33 | <key>UIUserInterfaceStyle</key> 34 | <string>Automatic</string> 35 | </dict> 36 | </plist> 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 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="11134" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc"> 3 | <dependencies> 4 | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/> 5 | <plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="11055"/> 6 | </dependencies> 7 | <scenes> 8 | <!--Interface Controller--> 9 | <scene sceneID="aou-V4-d1y"> 10 | <objects> 11 | <controller id="AgC-eL-Hgc" customClass="InterfaceController" customModuleProvider="target"/> 12 | </objects> 13 | </scene> 14 | </scenes> 15 | </document> 16 | -------------------------------------------------------------------------------- /DemoSwiftApp/DemoSwiftwatchOS WatchKit App/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>$(DEVELOPMENT_LANGUAGE)</string> 7 | <key>CFBundleDisplayName</key> 8 | <string>DemoSwiftwatchOS WatchKit App</string> 9 | <key>CFBundleExecutable</key> 10 | <string>$(EXECUTABLE_NAME)</string> 11 | <key>CFBundleIdentifier</key> 12 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 13 | <key>CFBundleInfoDictionaryVersion</key> 14 | <string>6.0</string> 15 | <key>CFBundleName</key> 16 | <string>$(PRODUCT_NAME)</string> 17 | <key>CFBundlePackageType</key> 18 | <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> 19 | <key>CFBundleShortVersionString</key> 20 | <string>1.0</string> 21 | <key>CFBundleVersion</key> 22 | <string>1</string> 23 | <key>UISupportedInterfaceOrientations</key> 24 | <array> 25 | <string>UIInterfaceOrientationPortrait</string> 26 | <string>UIInterfaceOrientationPortraitUpsideDown</string> 27 | </array> 28 | <key>WKWatchKitApp</key> 29 | <true/> 30 | </dict> 31 | </plist> 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>$(DEVELOPMENT_LANGUAGE)</string> 7 | <key>CFBundleDisplayName</key> 8 | <string>DemoSwiftwatchOS WatchKit Extension</string> 9 | <key>CFBundleExecutable</key> 10 | <string>$(EXECUTABLE_NAME)</string> 11 | <key>CFBundleIdentifier</key> 12 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 13 | <key>CFBundleInfoDictionaryVersion</key> 14 | <string>6.0</string> 15 | <key>CFBundleName</key> 16 | <string>$(PRODUCT_NAME)</string> 17 | <key>CFBundlePackageType</key> 18 | <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> 19 | <key>CFBundleShortVersionString</key> 20 | <string>1.0</string> 21 | <key>CFBundleVersion</key> 22 | <string>1</string> 23 | <key>NSExtension</key> 24 | <dict> 25 | <key>NSExtensionAttributes</key> 26 | <dict> 27 | <key>WKAppBundleIdentifier</key> 28 | <string>com.optimizely.DemoSwiftwatchOS.watchkitapp</string> 29 | </dict> 30 | <key>NSExtensionPointIdentifier</key> 31 | <string>com.apple.watchkit</string> 32 | </dict> 33 | <key>WKExtensionDelegateClassName</key> 34 | <string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string> 35 | <key>WKWatchOnly</key> 36 | <true/> 37 | </dict> 38 | </plist> 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict/> 5 | </plist> 6 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6E636B8B2236C91F00AF3CEF.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>runDestinationsByUUID</key> 6 | <dict> 7 | <key>2564B2A6-3658-41F8-8220-6CC2F6018D25</key> 8 | <dict> 9 | <key>localComputer</key> 10 | <dict> 11 | <key>busSpeedInMHz</key> 12 | <integer>100</integer> 13 | <key>cpuCount</key> 14 | <integer>1</integer> 15 | <key>cpuKind</key> 16 | <string>Intel Core i7</string> 17 | <key>cpuSpeedInMHz</key> 18 | <integer>2500</integer> 19 | <key>logicalCPUCoresPerPackage</key> 20 | <integer>8</integer> 21 | <key>modelCode</key> 22 | <string>MacBookPro11,4</string> 23 | <key>physicalCPUCoresPerPackage</key> 24 | <integer>4</integer> 25 | <key>platformIdentifier</key> 26 | <string>com.apple.platform.macosx</string> 27 | </dict> 28 | <key>targetArchitecture</key> 29 | <string>x86_64</string> 30 | <key>targetDevice</key> 31 | <dict> 32 | <key>modelCode</key> 33 | <string>iPhone11,8</string> 34 | <key>platformIdentifier</key> 35 | <string>com.apple.platform.iphonesimulator</string> 36 | </dict> 37 | </dict> 38 | </dict> 39 | </dict> 40 | </plist> 41 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6EBAEB7321E3FEF900D13AA9.xcbaseline/97A8F182-0DA1-4499-B20E-185EB633EA3E.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>classNames</key> 6 | <dict> 7 | <key>OptimizelyManagerTests</key> 8 | <dict> 9 | <key>testPerformanceBasicExperiment()</key> 10 | <dict> 11 | <key>com.apple.XCTPerformanceMetric_WallClockTime</key> 12 | <dict> 13 | <key>baselineAverage</key> 14 | <real>0.0014232</real> 15 | <key>baselineIntegrationDisplayName</key> 16 | <string>Local Baseline</string> 17 | </dict> 18 | </dict> 19 | <key>testPerformanceInitialize()</key> 20 | <dict> 21 | <key>com.apple.XCTPerformanceMetric_WallClockTime</key> 22 | <dict> 23 | <key>baselineAverage</key> 24 | <real>0.0037978</real> 25 | <key>baselineIntegrationDisplayName</key> 26 | <string>Local Baseline</string> 27 | </dict> 28 | </dict> 29 | <key>testPerformanceTypedAudience()</key> 30 | <dict> 31 | <key>com.apple.XCTPerformanceMetric_WallClockTime</key> 32 | <dict> 33 | <key>baselineAverage</key> 34 | <real>0.0043147</real> 35 | <key>baselineIntegrationDisplayName</key> 36 | <string>Local Baseline</string> 37 | </dict> 38 | </dict> 39 | </dict> 40 | </dict> 41 | </dict> 42 | </plist> 43 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcodeproj/xcshareddata/xcbaselines/6EBAEB7321E3FEF900D13AA9.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>runDestinationsByUUID</key> 6 | <dict> 7 | <key>97A8F182-0DA1-4499-B20E-185EB633EA3E</key> 8 | <dict> 9 | <key>localComputer</key> 10 | <dict> 11 | <key>busSpeedInMHz</key> 12 | <integer>100</integer> 13 | <key>cpuCount</key> 14 | <integer>1</integer> 15 | <key>cpuKind</key> 16 | <string>Intel Core i7</string> 17 | <key>cpuSpeedInMHz</key> 18 | <integer>2500</integer> 19 | <key>logicalCPUCoresPerPackage</key> 20 | <integer>8</integer> 21 | <key>modelCode</key> 22 | <string>MacBookPro11,4</string> 23 | <key>physicalCPUCoresPerPackage</key> 24 | <integer>4</integer> 25 | <key>platformIdentifier</key> 26 | <string>com.apple.platform.macosx</string> 27 | </dict> 28 | <key>targetArchitecture</key> 29 | <string>x86_64</string> 30 | <key>targetDevice</key> 31 | <dict> 32 | <key>modelCode</key> 33 | <string>iPhone11,8</string> 34 | <key>platformIdentifier</key> 35 | <string>com.apple.platform.iphonesimulator</string> 36 | </dict> 37 | </dict> 38 | </dict> 39 | </dict> 40 | </plist> 41 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <Workspace 3 | version = "1.0"> 4 | <FileRef 5 | location = "group:DemoSwiftApp/DemoSwiftApp.xcodeproj"> 6 | </FileRef> 7 | <FileRef 8 | location = "group:DemoObjcApp/DemoObjcApp.xcodeproj"> 9 | </FileRef> 10 | <FileRef 11 | location = "group:OptimizelySwiftSDK.xcodeproj"> 12 | </FileRef> 13 | <FileRef 14 | location = "group:Pods/Pods.xcodeproj"> 15 | </FileRef> 16 | <FileRef 17 | location = "group:OptimizelySwiftSDK.podspec"> 18 | </FileRef> 19 | <FileRef 20 | location = "group:Package.swift"> 21 | </FileRef> 22 | </Workspace> 23 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcworkspace/xcshareddata/IDETemplateMacros.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>FILEHEADER</key> 6 | <string> 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 | //</string> 21 | </dict> 22 | </plist> 23 | 24 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>IDEDidComputeMac32BitWarning</key> 6 | <true/> 7 | </dict> 8 | </plist> 9 | -------------------------------------------------------------------------------- /OptimizelySwiftSDK.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>PreviewsEnabled</key> 6 | <false/> 7 | </dict> 8 | </plist> 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 <file>" 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 <folder>" 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<<EOF 7 | import Foundation 8 | 9 | let fs = FileManager.default 10 | 11 | let data = fs.contents(atPath: "../OptimizelySDK/Utils/OptimizelySDKVersion.swift") 12 | 13 | let str = String(data: data!, encoding: .utf8) 14 | 15 | let newStr = str!.replacingOccurrences(of: "$oldName", with: "$newName") 16 | 17 | try newStr.write(to: URL(fileURLWithPath: "../OptimizelySDK/Utils/OptimizelySDKVersion.swift"), atomically: true, encoding: .utf8) 18 | 19 | EOF 20 | } 21 | echo "$(swift_code)" | swift - 22 | -------------------------------------------------------------------------------- /Scripts/test_all.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash -e 3 | # 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. 4 | # We must use old simulators with current xcode since older xcode versions do not support swift 5 which is required by Swift SDK. 5 | # 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 6 | # https://github.com/actions/virtual-environments/issues/551 7 | 8 | deviceModels=("iPhone 12" "iPhone 8" "iPad Air (4th generation)" "Apple TV") 9 | osVersions=("16.0" "14.4" "15.0" "16.0") 10 | xcodeVersions=("14.3" "14.3" "14.3" "14.3") 11 | platforms=("iOS" "iOS" "iOS" "tvOS") 12 | testSdks=("iphonesimulator" "iphonesimulator" "iphonesimulator" "appletvsimulator") 13 | 14 | for i in "${!deviceModels[@]}"; do 15 | export PLATFORM="${platforms[$i]} Simulator" 16 | export OS="${osVersions[$i]}" 17 | export NAME="${deviceModels[$i]}" 18 | export OS_TYPE="${platforms[$i]}" 19 | export SIMULATOR_XCODE_VERSION="${xcodeVersions[$i]}" 20 | 21 | Scripts/prepare_simulator.sh 22 | echo "Testing OptimizelySwiftSDK-${platforms[$i]} (${deviceModels[$i]},OS=${osVersions[$i]})" 23 | 24 | xcrun xcodebuild -workspace OptimizelySwiftSDK.xcworkspace -scheme "OptimizelySwiftSDK-${platforms[$i]}" -sdk "${testSdks[$i]}" -configuration Release -destination "platform=${platforms[$i]} Simulator,name=${deviceModels[$i]},OS=${osVersions[$i]}" test 25 | done 26 | -------------------------------------------------------------------------------- /Sources/Customization/DefaultLogger.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 os.log 19 | 20 | open class DefaultLogger: OPTLogger { 21 | private static var _logLevel: OptimizelyLogLevel? 22 | public static var logLevel: OptimizelyLogLevel { 23 | get { 24 | return _logLevel ?? .info 25 | } 26 | set (newLevel) { 27 | if _logLevel == nil { 28 | _logLevel = newLevel 29 | } 30 | } 31 | } 32 | 33 | required public init() {} 34 | 35 | open func log(level: OptimizelyLogLevel, message: String) { 36 | if level > 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<Data>) -> 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<T> { 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<Value> { 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>$(DEVELOPMENT_LANGUAGE)</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>FMWK</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>$(CURRENT_PROJECT_VERSION)</string> 19 | <key>CFBundleVersion</key> 20 | <string>$(CURRENT_PROJECT_VERSION)</string> 21 | </dict> 22 | </plist> 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 <Optimizely/PublicHeader.h> 26 | 27 | 28 | -------------------------------------------------------------------------------- /Sources/Supporting Files/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>NSPrivacyCollectedDataTypes</key> 6 | <array> 7 | <dict> 8 | <key>NSPrivacyCollectedDataType</key> 9 | <string>NSPrivacyCollectedDataTypeProductInteraction</string> 10 | <key>NSPrivacyCollectedDataTypeLinked</key> 11 | <false/> 12 | <key>NSPrivacyCollectedDataTypeTracking</key> 13 | <false/> 14 | <key>NSPrivacyCollectedDataTypePurposes</key> 15 | <array> 16 | <string>NSPrivacyCollectedDataTypePurposeAnalytics</string> 17 | </array> 18 | </dict> 19 | </array> 20 | <key>NSPrivacyAccessedAPITypes</key> 21 | <array> 22 | <dict> 23 | <key>NSPrivacyAccessedAPIType</key> 24 | <string>NSPrivacyAccessedAPICategoryUserDefaults</string> 25 | <key>NSPrivacyAccessedAPITypeReasons</key> 26 | <array> 27 | <string>CA92.1</string> 28 | </array> 29 | </dict> 30 | </array> 31 | </dict> 32 | </plist> 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<K: Hashable, V>: 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<T> { 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 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>CFBundleDevelopmentRegion</key> 6 | <string>$(DEVELOPMENT_LANGUAGE)</string> 7 | <key>CFBundleExecutable</key> 8 | <string>$(EXECUTABLE_NAME)</string> 9 | <key>CFBundleIdentifier</key> 10 | <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> 11 | <key>CFBundleInfoDictionaryVersion</key> 12 | <string>6.0</string> 13 | <key>CFBundleName</key> 14 | <string>$(PRODUCT_NAME)</string> 15 | <key>CFBundlePackageType</key> 16 | <string>BNDL</string> 17 | <key>CFBundleShortVersionString</key> 18 | <string>1.0</string> 19 | <key>CFBundleVersion</key> 20 | <string>1</string> 21 | </dict> 22 | </plist> 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..<numEventsPerThread { 32 | let userId = String(idx) 33 | let experimentId = String((thIdx * numEventsPerThread) + idx) 34 | let variationId = experimentId 35 | 36 | self.config.whitelistUser(userId: userId, experimentId: experimentId, variationId: variationId) 37 | var result = self.config.getWhitelistedVariationId(userId: userId, experimentId: experimentId) 38 | XCTAssertEqual(result, variationId) 39 | 40 | self.config.removeFromWhitelist(userId: userId, experimentId: experimentId) 41 | result = self.config.getWhitelistedVariationId(userId: userId, experimentId: experimentId) 42 | XCTAssertNil(result) 43 | } 44 | } 45 | 46 | XCTAssertTrue(result, "Concurrent tasks timed out") 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Tests/OptimizelyTests-Others/OtherTests.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 OtherTests: XCTestCase { 20 | 21 | func testSDKVersionFormat() { 22 | let version = Utils.sdkVersion 23 | XCTAssert(version.split(separator: ".").count == 3) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/OptimizelyTests-iOS/iOSOnlyTests.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 iOSOnlyTests: XCTestCase { 20 | 21 | override func setUp() { 22 | // Put setup code here. This method is called before the invocation of each test method in the class. 23 | } 24 | 25 | override func tearDown() { 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | } 28 | 29 | func testExample() { 30 | // This is an example of a functional test case. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Tests/OptimizelyTests-tvOS/tvOSOnlyTests.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 tvOSOnlyTests: XCTestCase { 20 | 21 | override func setUp() { 22 | // Put setup code here. This method is called before the invocation of each test method in the class. 23 | } 24 | 25 | override func tearDown() { 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | } 28 | 29 | func testExample() { 30 | // This is an example of a functional test case. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Tests/TestData/bot_filtering_enabled.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "botFiltering": true, 6 | "projectId": "10431130345", 7 | "variables": [], 8 | "featureFlags": [], 9 | "experiments": [ 10 | { 11 | "status": "Running", 12 | "key": "ab_running_exp_untargeted", 13 | "layerId": "10417730432", 14 | "trafficAllocation": [ 15 | { 16 | "entityId": "10418551353", 17 | "endOfRange": 10000 18 | } 19 | ], 20 | "audienceIds": [], 21 | "variations": [ 22 | { 23 | "variables": [], 24 | "id": "10418551353", 25 | "key": "all_traffic_variation" 26 | }, 27 | { 28 | "variables": [], 29 | "id": "10418510624", 30 | "key": "a" 31 | } 32 | ], 33 | "forcedVariations": { 34 | "whitelisted_user_var_a": "a", 35 | "whitelisted_user_var_b": "all_traffic_variation", 36 | "whitelisted_user_invalid_var": "invalid_var" 37 | }, 38 | "id": "10420810910" 39 | } 40 | ], 41 | "audiences": [], 42 | "groups": [], 43 | "attributes": [], 44 | "accountId": "10367498574", 45 | "events": [ 46 | { 47 | "experimentIds": [ 48 | "10420810910" 49 | ], 50 | "id": "10404198134", 51 | "key": "event_with_running_exp" 52 | } 53 | ], 54 | "revision": "241" 55 | } 56 | -------------------------------------------------------------------------------- /Tests/TestData/bucketer_test3.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [ 4 | { 5 | "experiments": [ 6 | { 7 | "status": "Running", 8 | "audienceIds": [ ], 9 | "variations": [ 10 | { 11 | "variables": [ ], 12 | "id": "18532971919", 13 | "key": "18532971919", 14 | "featureEnabled": true 15 | } 16 | ], 17 | "id": "18513703488", 18 | "key": "18513703488", 19 | "layerId": "18513932701", 20 | "trafficAllocation": [ 21 | { 22 | "entityId": "18532971919", 23 | "endOfRange": 0 24 | } 25 | ], 26 | "forcedVariations": { } 27 | } 28 | ], 29 | "id": "18513932701" 30 | } 31 | ], 32 | "anonymizeIP": true, 33 | "projectId": "10431130345", 34 | "variables": [], 35 | "featureFlags": [ 36 | { 37 | "experimentIds": [], 38 | "rolloutId": "18513932701", 39 | "variables": [], 40 | "id": "18533552281", 41 | "key": "async_payments" 42 | } 43 | ], 44 | "experiments": [], 45 | "audiences": [], 46 | "groups": [], 47 | "attributes": [], 48 | "accountId": "10367498574", 49 | "events": [], 50 | "revision": "100" 51 | } 52 | -------------------------------------------------------------------------------- /Tests/TestData/empty_datafile.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [], 9 | "audiences": [], 10 | "groups": [], 11 | "attributes": [], 12 | "accountId": "10367498574", 13 | "events": [], 14 | "revision": "100" 15 | } 16 | -------------------------------------------------------------------------------- /Tests/TestData/empty_datafile_new_account_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [], 9 | "audiences": [], 10 | "groups": [], 11 | "attributes": [], 12 | "accountId": "111111111", 13 | "events": [], 14 | "revision": "100" 15 | } 16 | -------------------------------------------------------------------------------- /Tests/TestData/empty_datafile_new_project_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "342312423", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [], 9 | "audiences": [], 10 | "groups": [], 11 | "attributes": [], 12 | "accountId": "10367498574", 13 | "events": [], 14 | "revision": "100" 15 | } 16 | -------------------------------------------------------------------------------- /Tests/TestData/empty_datafile_new_revision.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [], 9 | "audiences": [], 10 | "groups": [], 11 | "attributes": [], 12 | "accountId": "10367498574", 13 | "events": [], 14 | "revision": "13421" 15 | } 16 | -------------------------------------------------------------------------------- /Tests/TestData/feature_flag.json: -------------------------------------------------------------------------------- 1 | { 2 | "accountId": "3321510822", 3 | "anonymizeIP": true, 4 | "attributes": [], 5 | "audiences": [], 6 | "events": [], 7 | "experiments": [], 8 | "featureFlags": [ 9 | { 10 | "experimentIds": [], 11 | "id": "3319590479", 12 | "key": "feature_flag", 13 | "rolloutId": "3319450668", 14 | "variables": [ 15 | { 16 | "defaultValue": "true", 17 | "id": "3321680886", 18 | "key": "b", 19 | "type": "boolean" 20 | }, 21 | { 22 | "defaultValue": "3", 23 | "id": "3323790746", 24 | "key": "i", 25 | "type": "integer" 26 | }, 27 | { 28 | "defaultValue": "10.5", 29 | "id": "3331590078", 30 | "key": "d", 31 | "type": "double" 32 | }, 33 | { 34 | "defaultValue": "s", 35 | "id": "3331600005", 36 | "key": "s", 37 | "type": "string" 38 | } 39 | ] 40 | } 41 | ], 42 | "groups": [], 43 | "projectId": "3321510822", 44 | "revision": "3", 45 | "rollouts": [ 46 | { 47 | "experiments": [ 48 | { 49 | "audienceIds": [], 50 | "forcedVariations": {}, 51 | "id": "3332020494", 52 | "key": "3332020494", 53 | "layerId": "3319450668", 54 | "status": "Not started", 55 | "trafficAllocation": [ 56 | { 57 | "endOfRange": 10000, 58 | "entityId": "3324490562" 59 | } 60 | ], 61 | "variations": [ 62 | { 63 | "featureEnabled": true, 64 | "id": "3324490562", 65 | "key": "3324490562", 66 | "variables": [] 67 | } 68 | ] 69 | } 70 | ], 71 | "id": "3319450668" 72 | } 73 | ], 74 | "variables": [], 75 | "version": "4" 76 | } 77 | -------------------------------------------------------------------------------- /Tests/TestData/feature_management_experiment_bucketing.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [ 8 | { 9 | "experimentIds": ["10373259356"], 10 | "rolloutId": "", 11 | "variables": [], 12 | "id": "10396278033", 13 | "key": "draft_experiment_feat" 14 | }, 15 | { 16 | "experimentIds": ["10373259356"], 17 | "rolloutId": "", 18 | "variables": [], 19 | "id": "10396278033", 20 | "key": "draft_experiment_feat" 21 | } 22 | ], 23 | "experiments": [ 24 | { 25 | "status": "Not started", 26 | "key": "draft_experiment", 27 | "layerId": "10418820769", 28 | "trafficAllocation": [ 29 | { 30 | "entityId": "10373549841", 31 | "endOfRange": 10000 32 | } 33 | ], 34 | "audienceIds": [], 35 | "variations": [], 36 | "forcedVariations": {}, 37 | "id": "10373259356" 38 | } 39 | ], 40 | "audiences": [], 41 | "groups": [], 42 | "attributes": [], 43 | "accountId": "10367498574", 44 | "events": [], 45 | "revision": "241" 46 | } 47 | -------------------------------------------------------------------------------- /Tests/TestData/forced_variation.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [ 9 | { 10 | "status": "Running", 11 | "key": "the_experiment", 12 | "layerId": "10418820769", 13 | "trafficAllocation": [ 14 | { 15 | "entityId": "10373549841", 16 | "endOfRange": 10000 17 | } 18 | ], 19 | "audienceIds": [], 20 | "variations": [ 21 | { 22 | "variables": [], 23 | "id": "10373549841", 24 | "key": "enabled_variation" 25 | }, 26 | { 27 | "variables": [], 28 | "id": "10373549842", 29 | "key": "hidden_variation" 30 | } 31 | ], 32 | "forcedVariations": {}, 33 | "id": "10373259356" 34 | }, 35 | { 36 | "status": "Running", 37 | "key": "the_targeted_experiment", 38 | "layerId": "10418820768", 39 | "trafficAllocation": [ 40 | { 41 | "entityId": "10373549851", 42 | "endOfRange": 10000 43 | } 44 | ], 45 | "audienceIds": ["2698010096"], 46 | "variations": [ 47 | { 48 | "variables": [], 49 | "id": "10373549851", 50 | "key": "enabled_variation" 51 | }, 52 | { 53 | "variables": [], 54 | "id": "10373549852", 55 | "key": "hidden_variation" 56 | } 57 | ], 58 | "forcedVariations": {}, 59 | "id": "10373259357" 60 | } 61 | ], 62 | "audiences": [ 63 | { 64 | "conditions": "[\"and\", {\"type\": \"custom_attribute\", \"name\": \"customattr\", \"value\": \"yes\"}]", 65 | "id": "2698010096", 66 | "name": "feature_audience" 67 | } 68 | ], 69 | "groups": [], 70 | "attributes": [], 71 | "accountId": "10367498574", 72 | "events": [], 73 | "revision": "241" 74 | } 75 | -------------------------------------------------------------------------------- /Tests/TestData/odp/odp_integrated_no_segments.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [], 9 | "audiences": [], 10 | "groups": [], 11 | "attributes": [], 12 | "accountId": "10367498574", 13 | "events": [], 14 | "integrations": [ 15 | { 16 | "key": "odp", 17 | "host": "https://api.zaius.com", 18 | "publicKey": "W4WzcEs-ABgXorzY7h1LCQ" 19 | } 20 | ], 21 | "revision": "100" 22 | } 23 | -------------------------------------------------------------------------------- /Tests/TestData/simple_datafile.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "botFiltering": true, 6 | "projectId": "10431130345", 7 | "variables": [], 8 | "featureFlags": [], 9 | "experiments": [ 10 | { 11 | "status": "Running", 12 | "key": "exp_with_audience", 13 | "layerId": "10420273888", 14 | "trafficAllocation": [ 15 | { 16 | "entityId": "10416523121", 17 | "endOfRange": 10000 18 | } 19 | ], 20 | "audienceIds": [ 21 | "10413101795" 22 | ], 23 | "variations": [ 24 | { 25 | "variables": [], 26 | "id": "10389729780", 27 | "key": "a" 28 | }, 29 | { 30 | "variables": [], 31 | "id": "10416523121", 32 | "key": "b" 33 | } 34 | ], 35 | "forcedVariations": {}, 36 | "id": "10390977673" 37 | }, 38 | { 39 | "status": "Running", 40 | "key": "exp_no_audience", 41 | "layerId": "10417730432", 42 | "trafficAllocation": [ 43 | { 44 | "entityId": "10418551353", 45 | "endOfRange": 10000 46 | } 47 | ], 48 | "audienceIds": [], 49 | "variations": [ 50 | { 51 | "variables": [], 52 | "id": "10418551353", 53 | "key": "variation_with_traffic" 54 | }, 55 | { 56 | "variables": [], 57 | "id": "10418510624", 58 | "key": "variation_no_traffic" 59 | } 60 | ], 61 | "forcedVariations": {}, 62 | "id": "10420810910" 63 | } 64 | ], 65 | "audiences": [ 66 | { 67 | "id": "10413101795", 68 | "conditions": "[\"and\", [\"or\", [\"or\", {\"type\": \"custom_attribute\", \"name\": \"testvar\", \"value\": \"testvalue\"}]]]", 69 | "name": "testvalue_audience" 70 | } 71 | ], 72 | "groups": [], 73 | "attributes": [ 74 | { 75 | "id": "10401066170", 76 | "key": "testvar" 77 | } 78 | ], 79 | "accountId": "10367498574", 80 | "events": [ 81 | { 82 | "experimentIds": [ 83 | "10420810910" 84 | ], 85 | "id": "10404198134", 86 | "key": "event1" 87 | }, 88 | { 89 | "experimentIds": [ 90 | "10420810910", 91 | "10390977673" 92 | ], 93 | "id": "10404198135", 94 | "key": "event_multiple_running_exp_attached" 95 | } 96 | ], 97 | "revision": "241" 98 | } 99 | -------------------------------------------------------------------------------- /Tests/TestData/unsupported_datafile.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "999", 3 | "rollouts": [], 4 | "anonymizeIP": true, 5 | "projectId": "10431130345", 6 | "variables": [], 7 | "featureFlags": [], 8 | "experiments": [ 9 | { 10 | "status": "Running", 11 | "key": "ab_running_exp_untargeted", 12 | "layerId": "10417730432", 13 | "trafficAllocation": [ 14 | { 15 | "entityId": "10418551353", 16 | "endOfRange": 10000 17 | } 18 | ], 19 | "audienceIds": [], 20 | "variations": [ 21 | { 22 | "variables": [], 23 | "id": "10418551353", 24 | "key": "all_traffic_variation" 25 | }, 26 | { 27 | "variables": [], 28 | "id": "10418510624", 29 | "key": "no_traffic_variation" 30 | } 31 | ], 32 | "forcedVariations": {}, 33 | "id": "10420810910" 34 | } 35 | ], 36 | "audiences": [], 37 | "groups": [], 38 | "attributes": [], 39 | "accountId": "10367498574", 40 | "events": [ 41 | { 42 | "experimentIds": [ 43 | "10420810910" 44 | ], 45 | "id": "10404198134", 46 | "key": "winning" 47 | } 48 | ], 49 | "revision": "1337" 50 | } 51 | -------------------------------------------------------------------------------- /Tests/TestUtils/MockBucketer.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 | 18 | // MARK: - Helper for mocking bucketer 19 | 20 | class MockBucketer: DefaultBucketer { 21 | var mockBucketValue: Int 22 | 23 | init(mockBucketValue: Int) { 24 | self.mockBucketValue = mockBucketValue 25 | super.init() 26 | } 27 | 28 | override func generateBucketValue(bucketingId: String) -> 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 | --------------------------------------------------------------------------------