@@ -45,7 +45,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
45
45
46
46
/// Part of FlutterPlugin protocol to handle communication with flutter sdk
47
47
public func handle( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
48
-
48
+
49
49
switch call. method {
50
50
case API . initialize: initialize ( call, result: result)
51
51
case API . addNotificationListener: addNotificationListener ( call, result: result)
@@ -67,6 +67,14 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
67
67
case API . removeForcedDecision: removeForcedDecision ( call, result: result)
68
68
case API . removeAllForcedDecisions: removeAllForcedDecisions ( call, result: result)
69
69
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)
70
78
default : result ( FlutterMethodNotImplemented)
71
79
}
72
80
}
@@ -99,6 +107,31 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
99
107
}
100
108
let defaultDecideOptions = Utils . getDecideOptions ( options: decideOptions)
101
109
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
+
102
135
// Datafile Download Interval
103
136
var datafilePeriodicDownloadInterval = 10 * 60 // seconds
104
137
@@ -119,7 +152,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
119
152
optimizelyClientsTracker. removeValue ( forKey: sdkKey)
120
153
121
154
// 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 )
123
156
124
157
optimizelyInstance. start { [ weak self] res in
125
158
switch res {
@@ -198,7 +231,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
198
231
guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
199
232
return
200
233
}
201
-
234
+
202
235
if let type = parameters [ RequestParameterKey . notificationType] as? String , let convertedNotificationType = Utils . getNotificationType ( type: type) {
203
236
// Remove listeners only for the provided type
204
237
optimizelyClient. notificationCenter? . clearNotificationListeners ( type: convertedNotificationType)
@@ -302,7 +335,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
302
335
let success = optimizelyClient. setForcedVariation ( experimentKey: experimentKey, userId: userId, variationKey: variationKey)
303
336
result ( self . createResponse ( success: success) )
304
337
}
305
-
338
+
306
339
/// Creates a context of the user for which decision APIs will be called.
307
340
/// A user context will only be created successfully when the SDK is fully configured using initializeClient.
308
341
func createUserContext( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
@@ -312,13 +345,15 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
312
345
guard let optimizelyClient = getOptimizelyClient ( sdkKey: sdkKey, result: result) else {
313
346
return
314
347
}
315
- guard let userId = parameters [ RequestParameterKey . userId] as? String else {
316
- result ( createResponse ( success: false , reason: ErrorMessage . invalidParameters) )
317
- return
318
- }
319
348
320
349
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
+ }
322
357
if userContextsTracker [ sdkKey] != nil {
323
358
userContextsTracker [ sdkKey] ![ userContextId] = userContext
324
359
} else {
@@ -359,6 +394,108 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin {
359
394
result ( createResponse ( success: true ) )
360
395
}
361
396
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
+
362
499
/// Tracks an event.
363
500
func trackEvent( _ call: FlutterMethodCall , result: @escaping FlutterResult ) {
364
501
guard let ( parameters, userContext) = getParametersAndUserContext ( arguments: call. arguments, result: result) else {
0 commit comments