diff --git a/splitio/lib/splitio.dart b/splitio/lib/splitio.dart index 3db1151..f20b066 100644 --- a/splitio/lib/splitio.dart +++ b/splitio/lib/splitio.dart @@ -121,6 +121,14 @@ class Splitio { return _platform.split(splitName: splitName); } + Future getUserConsent() async { + return _platform.getUserConsent(); + } + + Future setUserConsent(bool enabled) async { + return _platform.setUserConsent(enabled); + } + Future _init() { return _platform.init( apiKey: _sdkKey, diff --git a/splitio/pubspec.yaml b/splitio/pubspec.yaml index 650fcbc..1437b31 100644 --- a/splitio/pubspec.yaml +++ b/splitio/pubspec.yaml @@ -19,9 +19,15 @@ flutter: dependencies: flutter: sdk: flutter - splitio_android: ^0.1.3 - splitio_ios: ^0.1.3 - splitio_platform_interface: ^1.1.0 +# splitio_android: ^0.1.3 + splitio_android: + path: ../splitio_android +# splitio_ios: ^0.1.3 + splitio_ios: + path: ../splitio_ios +# splitio_platform_interface: ^1.1.0 + splitio_platform_interface: + path: ../splitio_platform_interface dev_dependencies: flutter_test: diff --git a/splitio/test/splitio_platform_stub.dart b/splitio/test/splitio_platform_stub.dart index 29f1526..369cc83 100644 --- a/splitio/test/splitio_platform_stub.dart +++ b/splitio/test/splitio_platform_stub.dart @@ -339,4 +339,19 @@ class SplitioPlatformStub return Future.value(true); } + + @override + Future getUserConsent() { + methodName = 'getUserConsent'; + + return Future.value(UserConsent.granted); + } + + @override + Future setUserConsent(bool enabled) { + methodName = 'setUserConsent'; + methodArguments['value'] = enabled; + + return Future.value(null); + } } diff --git a/splitio/test/splitio_test.dart b/splitio/test/splitio_test.dart index ac227f2..87ad6e4 100644 --- a/splitio/test/splitio_test.dart +++ b/splitio/test/splitio_test.dart @@ -101,4 +101,26 @@ void main() { expect(_platform.methodArguments, {'splitName': 'my_split'}); }); }); + + group('userConsent', () { + test('get user consent', () async { + var splitio = Splitio('api-key', 'matching-key'); + splitio.getUserConsent(); + + expect(_platform.methodName, 'getUserConsent'); + }); + + test('set user consent', () async { + var splitio = Splitio('api-key', 'matching-key'); + splitio.setUserConsent(true); + + expect(_platform.methodName, 'setUserConsent'); + expect(_platform.methodArguments, { + 'matchingKey': 'matching-key', + 'apiKey': 'api-key', + 'sdkConfiguration': {}, + 'value': true, + }); + }); + }); } diff --git a/splitio_android/android/src/main/java/io/split/splitio/Constants.java b/splitio_android/android/src/main/java/io/split/splitio/Constants.java index 461a553..35ceb63 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/Constants.java +++ b/splitio_android/android/src/main/java/io/split/splitio/Constants.java @@ -26,6 +26,8 @@ static class Method { static final String SPLIT_NAMES = "splitNames"; static final String SPLIT = "split"; static final String IMPRESSION_LOG = "impressionLog"; + static final String GET_USER_CONSENT = "getUserConsent"; + static final String SET_USER_CONSENT = "setUserConsent"; } static class Argument { diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java index d3c7f1a..fb3ad5d 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java @@ -27,10 +27,12 @@ import static io.split.splitio.Constants.Method.GET_TREATMENTS; import static io.split.splitio.Constants.Method.GET_TREATMENTS_WITH_CONFIG; import static io.split.splitio.Constants.Method.GET_TREATMENT_WITH_CONFIG; +import static io.split.splitio.Constants.Method.GET_USER_CONSENT; import static io.split.splitio.Constants.Method.INIT; import static io.split.splitio.Constants.Method.REMOVE_ATTRIBUTE; import static io.split.splitio.Constants.Method.SET_ATTRIBUTE; import static io.split.splitio.Constants.Method.SET_ATTRIBUTES; +import static io.split.splitio.Constants.Method.SET_USER_CONSENT; import static io.split.splitio.Constants.Method.SPLIT; import static io.split.splitio.Constants.Method.SPLITS; import static io.split.splitio.Constants.Method.SPLIT_NAMES; @@ -195,6 +197,13 @@ public void onMethodCall(String methodName, Object arguments, @NonNull MethodCha case SPLIT: result.success(getSplitViewAsMap(mSplitWrapper.split(mArgumentParser.getStringArgument(SPLIT_NAME, arguments)))); break; + case GET_USER_CONSENT: + result.success(mSplitWrapper.getUserConsent()); + break; + case SET_USER_CONSENT: + mSplitWrapper.setUserConsent(mArgumentParser.getBooleanArgument(VALUE, arguments)); + result.success(null); + break; default: result.notImplemented(); break; diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapper.java b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapper.java index f1b9d4b..54faa28 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapper.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapper.java @@ -24,4 +24,8 @@ interface SplitWrapper extends EvaluationWrapper, AttributesWrapper { @Nullable SplitView split(String splitName); + + String getUserConsent(); + + void setUserConsent(boolean enabled); } diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java index ec90e0b..b445908 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java @@ -15,6 +15,7 @@ import io.split.android.client.SplitResult; import io.split.android.client.api.Key; import io.split.android.client.api.SplitView; +import io.split.android.client.shared.UserConsent; import io.split.android.client.utils.ConcurrentSet; import io.split.android.grammar.Treatments; @@ -222,4 +223,21 @@ public List splits() { public SplitView split(String splitName) { return mSplitFactory.manager().split(splitName); } + + @Override + public String getUserConsent() { + UserConsent userConsent = mSplitFactory.getUserConsent(); + if (userConsent == UserConsent.GRANTED) { + return "granted"; + } else if (userConsent == UserConsent.DECLINED) { + return "declined"; + } else { + return "unknown"; + } + } + + @Override + public void setUserConsent(boolean enabled) { + mSplitFactory.setUserConsent(enabled); + } } diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java index 3245c38..538ea0e 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java @@ -475,4 +475,33 @@ public void initialization() { eq("bucketing-key"), argThat(splitClientConfig -> splitClientConfig.impressionListener() != null && !splitClientConfig.streamingEnabled())); } + + @Test + public void getUserConsent() { + when(mSplitWrapper.getUserConsent()).thenReturn("granted"); + mMethodParser.onMethodCall("getUserConsent", Collections.emptyMap(), mResult); + + verify(mResult).success("granted"); + verify(mSplitWrapper).getUserConsent(); + } + + @Test + public void setUserConsentEnabled() { + when(mArgumentParser.getBooleanArgument("value", Collections.singletonMap("value", true))).thenReturn(true); + when(mArgumentParser.getBooleanArgument("value", Collections.singletonMap("value", false))).thenReturn(false); + mMethodParser.onMethodCall("setUserConsent", Collections.singletonMap("value", true), mResult); + + verify(mResult).success(null); + verify(mSplitWrapper).setUserConsent(true); + } + + @Test + public void setUserConsentDisabled() { + when(mArgumentParser.getBooleanArgument("value", Collections.singletonMap("value", true))).thenReturn(true); + when(mArgumentParser.getBooleanArgument("value", Collections.singletonMap("value", false))).thenReturn(false); + mMethodParser.onMethodCall("setUserConsent", Collections.singletonMap("value", false), mResult); + + verify(mResult).success(null); + verify(mSplitWrapper).setUserConsent(false); + } } diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java index ceb5572..200f785 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java @@ -22,6 +22,7 @@ import io.split.android.client.SplitFactory; import io.split.android.client.SplitManager; import io.split.android.client.api.Key; +import io.split.android.client.shared.UserConsent; public class SplitWrapperImplTest { @@ -277,4 +278,19 @@ public void testSplit() { verify(managerMock).split("my_split"); } + + @Test + public void testGetUserConsent() { + when(mSplitFactory.getUserConsent()).thenReturn(UserConsent.DECLINED); + String userConsent = mSplitWrapper.getUserConsent(); + + verify(mSplitFactory).getUserConsent(); + assertEquals("declined", userConsent); + } + + @Test + public void testSetUserConsent() { + mSplitWrapper.setUserConsent(true); + verify(mSplitFactory).setUserConsent(true); + } } diff --git a/splitio_android/pubspec.yaml b/splitio_android/pubspec.yaml index 33d267c..33684f1 100644 --- a/splitio_android/pubspec.yaml +++ b/splitio_android/pubspec.yaml @@ -19,7 +19,9 @@ flutter: dependencies: flutter: sdk: flutter - splitio_platform_interface: ^1.1.0 +# splitio_platform_interface: ^1.1.0 + splitio_platform_interface: + path: ../splitio_platform_interface dev_dependencies: flutter_test: diff --git a/splitio_android/test/splitio_android_test.dart b/splitio_android/test/splitio_android_test.dart index a2def3f..34d65a4 100644 --- a/splitio_android/test/splitio_android_test.dart +++ b/splitio_android/test/splitio_android_test.dart @@ -514,4 +514,27 @@ void main() { 'attributes': {} }); }); + + group('userConsent', () { + test('get user consent', () async { + UserConsent userConsent = await _platform.getUserConsent(); + + expect(methodName, 'getUserConsent'); + expect(userConsent, UserConsent.declined); + }); + + test('set user consent enabled', () { + _platform.setUserConsent(true); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'enabled': true}); + }); + + test('set user consent disabled', () { + _platform.setUserConsent(false); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'enabled': false}); + }); + }); } diff --git a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift index 12fa488..e2d96a2 100644 --- a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift @@ -297,6 +297,28 @@ class SplitMethodParserTests: XCTestCase { XCTAssert(providerHelper.splitClientConfigValue?.impressionListener != nil) XCTAssert(providerHelper.splitClientConfigValue?.streamingEnabled == false) } + + func testGetUserConsent() { + methodParser?.onMethodCall(methodName: "getUserConsent", arguments: [], result: { (_: Any?) in }) + + guard let wrapper = splitWrapper as? SplitWrapperStub else { + XCTFail() + return + } + + XCTAssert(wrapper.userConsent == "unknown") + } + + func testSetUserConsent() { + methodParser?.onMethodCall(methodName: "setUserConsent", arguments: [], result: { (_: Any?) in }) + + guard let wrapper = splitWrapper as? SplitWrapperStub else { + XCTFail() + return + } + + XCTAssert(wrapper.userConsent == "declined") + } } class SplitWrapperStub: SplitWrapper { @@ -316,6 +338,7 @@ class SplitWrapperStub: SplitWrapper { var attributeNameValue: String = "" var splitsCalled = false var splitNamesCalled = false + var userConsent = "unknown" func getClient(matchingKey: String, bucketingKey: String?) -> SplitClient? { matchingKeyValue = matchingKey @@ -440,6 +463,18 @@ class SplitWrapperStub: SplitWrapper { splitNameValue = splitName return nil } + + func getUserConsent() -> String { + return userConsent + } + + func setUserConsent(enabled: Bool) { + if (enabled) { + userConsent = "granted" + } else { + userConsent = "declined" + } + } } class SplitProviderHelperStub: SplitProviderHelper { diff --git a/splitio_ios/example/ios/SplitTests/SplitTests.swift b/splitio_ios/example/ios/SplitTests/SplitTests.swift index 7853301..e4c02ad 100644 --- a/splitio_ios/example/ios/SplitTests/SplitTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitTests.swift @@ -181,6 +181,26 @@ class SplitTests: XCTestCase { let split = splitWrapper.split(splitName: "my-split") XCTAssert(manager.splitNameValue == "my-split") } + + func testGetUserConsent() { + let manager = SplitManagerStub() + let factoryProvider = SplitFactoryProviderStub(manager: manager) + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: factoryProvider) + let userConsent = splitWrapper.getUserConsent() + XCTAssert(userConsent == "unknown") + } + + func testSetUserConsent() { + let manager = SplitManagerStub() + let factoryProvider = SplitFactoryProviderStub(manager: manager) + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: factoryProvider) + splitWrapper.setUserConsent(enabled: true) + let grantedUserConsent = splitWrapper.getUserConsent() + splitWrapper.setUserConsent(enabled: false) + let declinedUserConsent = splitWrapper.getUserConsent() + XCTAssert(grantedUserConsent == "granted") + XCTAssert(declinedUserConsent == "declined") + } } class SplitFactoryProviderStub: SplitFactoryProvider { diff --git a/splitio_ios/ios/Classes/Constants.swift b/splitio_ios/ios/Classes/Constants.swift index c5e6cce..bea9d65 100644 --- a/splitio_ios/ios/Classes/Constants.swift +++ b/splitio_ios/ios/Classes/Constants.swift @@ -24,6 +24,8 @@ enum Method: String { case splits = "splits" case split = "split" case impressionLog = "impressionLog" + case getUserConsent = "getUserConsent" + case setUserConsent = "setUserConsent" } enum Argument: String { diff --git a/splitio_ios/ios/Classes/SplitMethodParser.swift b/splitio_ios/ios/Classes/SplitMethodParser.swift index d4c6aba..6c8a216 100644 --- a/splitio_ios/ios/Classes/SplitMethodParser.swift +++ b/splitio_ios/ios/Classes/SplitMethodParser.swift @@ -133,6 +133,12 @@ class DefaultSplitMethodParser: SplitMethodParser { case .split: result(SplitView.asMap(splitView: splitWrapper?.split(splitName: argumentParser.getStringArgument(argumentName: .splitName, arguments: arguments) ?? ""))) break + case .getUserConsent: + result(splitWrapper?.getUserConsent()) + break + case .setUserConsent: + splitWrapper?.setUserConsent(enabled: argumentParser.getBooleanArgument(argumentName: .value, arguments: arguments)) + result(nil) default: result(FlutterMethodNotImplemented) break diff --git a/splitio_ios/ios/Classes/SplitWrapper.swift b/splitio_ios/ios/Classes/SplitWrapper.swift index f9b65d9..69e764f 100644 --- a/splitio_ios/ios/Classes/SplitWrapper.swift +++ b/splitio_ios/ios/Classes/SplitWrapper.swift @@ -16,6 +16,10 @@ protocol SplitWrapper: EvaluationWrapper, AttributesWrapper { func splits() -> [SplitView] func split(splitName: String) -> SplitView? + + func getUserConsent() -> String + + func setUserConsent(enabled: Bool) } protocol EvaluationWrapper { @@ -227,4 +231,26 @@ class DefaultSplitWrapper: SplitWrapper { return nil } } + + func getUserConsent() -> String { + if let splitFactory = splitFactory { + let userConsent: UserConsent = splitFactory.userConsent + + if (userConsent == .granted) { + return "granted" + } else if (userConsent == .declined) { + return "declined" + } else { + return "unknown" + } + } else { + return "unknown" + } + } + + func setUserConsent(enabled: Bool) { + if let splitFactory = splitFactory { + splitFactory.setUserConsent(enabled: enabled) + } + } } diff --git a/splitio_ios/pubspec.yaml b/splitio_ios/pubspec.yaml index 4481a13..a2dd2b9 100644 --- a/splitio_ios/pubspec.yaml +++ b/splitio_ios/pubspec.yaml @@ -18,7 +18,9 @@ flutter: dependencies: flutter: sdk: flutter - splitio_platform_interface: ^1.1.0 +# splitio_platform_interface: ^1.1.0 + splitio_platform_interface: + path: ../splitio_platform_interface dev_dependencies: flutter_test: diff --git a/splitio_platform_interface/lib/method_channel_platform.dart b/splitio_platform_interface/lib/method_channel_platform.dart index b499305..8132d28 100644 --- a/splitio_platform_interface/lib/method_channel_platform.dart +++ b/splitio_platform_interface/lib/method_channel_platform.dart @@ -324,6 +324,24 @@ class MethodChannelPlatform extends SplitioPlatform { return _impressionsMethodCallHandler.stream(); } + @override + Future getUserConsent() async { + String invokeMethod = + (await _methodChannel.invokeMethod('getUserConsent')) as String; + if (invokeMethod == 'granted') { + return UserConsent.granted; + } else if (invokeMethod == 'declined') { + return UserConsent.declined; + } else { + return UserConsent.unknown; + } + } + + @override + Future setUserConsent(bool enabled) async { + await _methodChannel.invokeMethod('setUserConsent', {'value': enabled}); + } + String _buildMapKey(String matchingKey, String? bucketingKey) { return '${matchingKey}_$bucketingKey'; } diff --git a/splitio_platform_interface/lib/splitio_platform_interface.dart b/splitio_platform_interface/lib/splitio_platform_interface.dart index 729e001..3e71adb 100644 --- a/splitio_platform_interface/lib/splitio_platform_interface.dart +++ b/splitio_platform_interface/lib/splitio_platform_interface.dart @@ -47,6 +47,14 @@ abstract class _FactoryPlatform { Stream impressionsStream() { throw UnimplementedError(); } + + Future getUserConsent() { + throw UnimplementedError(); + } + + Future setUserConsent(bool enabled) { + throw UnimplementedError(); + } } abstract class _ClientPlatform { diff --git a/splitio_platform_interface/test/method_channel_platform_test.dart b/splitio_platform_interface/test/method_channel_platform_test.dart index 72cb4ed..21ed1e2 100644 --- a/splitio_platform_interface/test/method_channel_platform_test.dart +++ b/splitio_platform_interface/test/method_channel_platform_test.dart @@ -54,6 +54,8 @@ void main() { case 'removeAttribute': case 'clearAttributes': return true; + case 'getUserConsent': + return 'declined'; } return null; }); @@ -372,8 +374,8 @@ void main() { apiKey: 'api-key', matchingKey: 'matching-key', bucketingKey: 'bucketing-key', - sdkConfiguration: - SplitConfiguration(logLevel: SplitLogLevel.debug, streamingEnabled: false)); + sdkConfiguration: SplitConfiguration( + logLevel: SplitLogLevel.debug, streamingEnabled: false)); expect(methodName, 'init'); expect(methodArguments, { 'apiKey': 'api-key', @@ -514,4 +516,27 @@ void main() { 'attributes': {} }); }); + + group('userConsent', () { + test('get user consent', () async { + UserConsent userConsent = await _platform.getUserConsent(); + + expect(methodName, 'getUserConsent'); + expect(userConsent, UserConsent.declined); + }); + + test('set user consent enabled', () { + _platform.setUserConsent(true); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'value': true}); + }); + + test('set user consent disabled', () { + _platform.setUserConsent(false); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'value': false}); + }); + }); }