@@ -45,7 +45,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
4545
4646 /// Part of FlutterPlugin protocol to handle communication with flutter sdk
4747 public func handle( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
48-
48+
4949 switch call. method {
5050 case API . initialize: initialize ( call, result: result)
5151 case API . addNotificationListener: addNotificationListener ( call, result: result)
@@ -67,6 +67,14 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
6767 case API . removeForcedDecision: removeForcedDecision ( call, result: result)
6868 case API . removeAllForcedDecisions: removeAllForcedDecisions ( call, result: result)
6969 case API . close: close ( call, result: result)
70+
71+ // ODP
72+ case API . getQualifiedSegments: getQualifiedSegments ( call, result: result)
73+ case API . setQualifiedSegments: setQualifiedSegments ( call, result: result)
74+ case API . getVuid: getVuid ( call, result: result)
75+ case API . isQualifiedFor: isQualifiedFor ( call, result: result)
76+ case API . sendOdpEvent: sendOdpEvent ( call, result: result)
77+ case API . fetchQualifiedSegments: fetchQualifiedSegments ( call, result: result)
7078 default : result ( FlutterMethodNotImplemented)
7179 }
7280 }
@@ -99,6 +107,31 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
99107 }
100108 let defaultDecideOptions = Utils . getDecideOptions ( options: decideOptions)
101109
110+ // SDK Settings Default Values
111+ var segmentsCacheSize : Int = 100
112+ var segmentsCacheTimeoutInSecs : Int = 600
113+ var timeoutForSegmentFetchInSecs : Int = 10
114+ var timeoutForOdpEventInSecs : Int = 10
115+ var disableOdp : Bool = false
116+ if let sdkSettings = parameters [ RequestParameterKey . optimizelySdkSettings] as? Dictionary < String , Any ? > {
117+ if let cacheSize = sdkSettings [ RequestParameterKey . segmentsCacheSize] as? Int {
118+ segmentsCacheSize = cacheSize
119+ }
120+ if let segmentsCacheTimeout = sdkSettings [ RequestParameterKey . segmentsCacheTimeoutInSecs] as? Int {
121+ segmentsCacheTimeoutInSecs = segmentsCacheTimeout
122+ }
123+ if let timeoutForSegmentFetch = sdkSettings [ RequestParameterKey . timeoutForSegmentFetchInSecs] as? Int {
124+ timeoutForSegmentFetchInSecs = timeoutForSegmentFetch
125+ }
126+ if let timeoutForOdpEvent = sdkSettings [ RequestParameterKey . timeoutForOdpEventInSecs] as? Int {
127+ timeoutForOdpEventInSecs = timeoutForOdpEvent
128+ }
129+ if let isOdpDisabled = sdkSettings [ RequestParameterKey . disableOdp] as? Bool {
130+ disableOdp = isOdpDisabled
131+ }
132+ }
133+ let optimizelySdkSettings = OptimizelySdkSettings ( segmentsCacheSize: segmentsCacheSize, segmentsCacheTimeoutInSecs: segmentsCacheTimeoutInSecs, timeoutForSegmentFetchInSecs: timeoutForSegmentFetchInSecs, timeoutForOdpEventInSecs: timeoutForOdpEventInSecs, disableOdp: disableOdp)
134+
102135 // Datafile Download Interval
103136 var datafilePeriodicDownloadInterval = 10 * 60 // seconds
104137
@@ -119,7 +152,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
119152 optimizelyClientsTracker. removeValue ( forKey: sdkKey)
120153
121154 // Creating new instance
122- let optimizelyInstance = OptimizelyClient ( sdkKey: sdkKey, eventDispatcher: eventDispatcher, datafileHandler: datafileHandler, periodicDownloadInterval: datafilePeriodicDownloadInterval, defaultDecideOptions: defaultDecideOptions)
155+ let optimizelyInstance = OptimizelyClient ( sdkKey: sdkKey, eventDispatcher: eventDispatcher, datafileHandler: datafileHandler, periodicDownloadInterval: datafilePeriodicDownloadInterval, defaultDecideOptions: defaultDecideOptions, settings : optimizelySdkSettings )
123156
124157 optimizelyInstance. start { [ weak self] res in
125158 switch res {
@@ -198,7 +231,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
198231 guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
199232 return
200233 }
201-
234+
202235 if let type = parameters [ RequestParameterKey . notificationType] as? String , let convertedNotificationType = Utils . getNotificationType ( type: type) {
203236 // Remove listeners only for the provided type
204237 optimizelyClient. notificationCenter? . clearNotificationListeners ( type: convertedNotificationType)
@@ -302,7 +335,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
302335 let success = optimizelyClient. setForcedVariation ( experimentKey: experimentKey, userId: userId, variationKey: variationKey)
303336 result ( self . createResponse ( success: success) )
304337 }
305-
338+
306339 /// Creates a context of the user for which decision APIs will be called.
307340 /// A user context will only be created successfully when the SDK is fully configured using initializeClient.
308341 func createUserContext( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
@@ -312,13 +345,15 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
312345 guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
313346 return
314347 }
315- guard let userId = parameters [ RequestParameterKey . userId] as? String else {
316- result ( createResponse ( success: false , reason: ErrorMessage . invalidParameters) )
317- return
318- }
319348
320349 let userContextId = uuid
321- let userContext = optimizelyClient. createUserContext ( userId: userId, attributes: Utils . getTypedMap ( arguments: parameters [ RequestParameterKey . attributes] as? Any ) )
350+ var userContext : OptimizelyUserContext !
351+
352+ if let userId = parameters [ RequestParameterKey . userId] as? String {
353+ userContext = optimizelyClient. createUserContext ( userId: userId, attributes: Utils . getTypedMap ( arguments: parameters [ RequestParameterKey . attributes] as? Any ) )
354+ } else {
355+ userContext = optimizelyClient. createUserContext ( attributes: Utils . getTypedMap ( arguments: parameters [ RequestParameterKey . attributes] as? Any ) )
356+ }
322357 if userContextsTracker [ sdkKey] != nil {
323358 userContextsTracker [ sdkKey] ![ userContextId] = userContext
324359 } else {
@@ -359,6 +394,108 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
359394 result ( createResponse ( success: true ) )
360395 }
361396
397+ /// Returns an array of segments that the user is qualified for.
398+ func getQualifiedSegments( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
399+ guard let ( _, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
400+ return
401+ }
402+ guard let qualifiedSegments = userContext. qualifiedSegments else {
403+ result ( createResponse ( success: false , reason: ErrorMessage . qualifiedSegmentsNotFound) )
404+ return
405+ }
406+ result ( createResponse ( success: true , result: [ RequestParameterKey . qualifiedSegments: qualifiedSegments] ) )
407+ }
408+
409+ /// Sets qualified segments for the user context.
410+ func setQualifiedSegments( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
411+ guard let ( parameters, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
412+ return
413+ }
414+ guard let qualifiedSegments = parameters [ RequestParameterKey . qualifiedSegments] as? [ String ] else {
415+ result ( createResponse ( success: false , reason: ErrorMessage . invalidParameters) )
416+ return
417+ }
418+ userContext. qualifiedSegments = qualifiedSegments
419+ result ( createResponse ( success: true ) )
420+ }
421+
422+ /// Returns the device vuid.
423+ func getVuid( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
424+ guard let ( _, sdkKey) = getParametersAndSdkKey ( arguments: call. arguments, result: result) else {
425+ return
426+ }
427+ guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
428+ return
429+ }
430+ result ( self . createResponse ( success: true , result: [ RequestParameterKey . vuid: optimizelyClient. vuid] ) )
431+ }
432+
433+ /// Checks if the user is qualified for the given segment.
434+ func isQualifiedFor( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
435+ guard let ( parameters, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
436+ return
437+ }
438+ guard let segment = parameters [ RequestParameterKey . segment] as? String else {
439+ result ( createResponse ( success: false , reason: ErrorMessage . invalidParameters) )
440+ return
441+ }
442+ result ( self . createResponse ( success: userContext. isQualifiedFor ( segment: segment) ) )
443+ }
444+
445+ /// Send an event to the ODP server.
446+ func sendOdpEvent( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
447+ guard let ( parameters, sdkKey) = getParametersAndSdkKey ( arguments: call. arguments, result: result) else {
448+ return
449+ }
450+ guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
451+ return
452+ }
453+ guard let action = parameters [ RequestParameterKey . action] as? String else {
454+ result ( createResponse ( success: false , reason: ErrorMessage . invalidParameters) )
455+ return
456+ }
457+
458+ var type : String ?
459+ var identifiers : [ String : String ] = [ : ]
460+ var data : [ String : Any ? ] = [ : ]
461+
462+ if let _type = parameters [ RequestParameterKey . type] as? String {
463+ type = _type
464+ }
465+ if let _identifiers = parameters [ RequestParameterKey . identifiers] as? Dictionary < String , String > {
466+ identifiers = _identifiers
467+ }
468+ if let _data = Utils . getTypedMap ( arguments: parameters [ RequestParameterKey . data] as? Any ) {
469+ data = _data
470+ }
471+
472+ do {
473+ try optimizelyClient. sendOdpEvent ( type: type, action: action, identifiers: identifiers, data: data)
474+ result ( self . createResponse ( success: true ) )
475+ } catch {
476+ result ( self . createResponse ( success: false , reason: error. localizedDescription) )
477+ }
478+ }
479+
480+ /// Fetch all qualified segments for the user context.
481+ func fetchQualifiedSegments( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
482+ guard let ( parameters, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
483+ return
484+ }
485+ var segmentOptions : [ String ] ?
486+ if let options = parameters [ RequestParameterKey . optimizelySegmentOption] as? [ String ] {
487+ segmentOptions = options
488+ }
489+
490+ let options = Utils . getSegmentOptions ( options: segmentOptions)
491+ do {
492+ try userContext. fetchQualifiedSegments ( options: options ?? [ ] )
493+ result ( createResponse ( success: true ) )
494+ } catch {
495+ result ( self . createResponse ( success: false , reason: error. localizedDescription) )
496+ }
497+ }
498+
362499 /// Tracks an event.
363500 func trackEvent( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
364501 guard let ( parameters, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
0 commit comments