diff --git a/CHANGELOG.md b/CHANGELOG.md index e77bfa912..d0b3bf7bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [13.3.0](https://github.com/Instabug/Instabug-Flutter/compare/v13.2.0...v13.3.0) (August 5, 2024) + +### Added + +- Add support for variants in Feature Flags through the APIs `Instabug.addFeatureFlags`, `Instabug.removeFeatureFlags` and `Instabug.clearAllFeatureFlags` ([#471](https://github.com/Instabug/Instabug-Flutter/pull/471)). + +### Changed + +- Bump Instabug Android SDK to v13.3.0 ([#492](https://github.com/Instabug/Instabug-Flutter/pull/492)). [See release notes](https://github.com/Instabug/Instabug-Android/releases/tag/v13.3.0). +- Bump Instabug iOS SDK to v13.3.0 ([#493](https://github.com/Instabug/Instabug-Flutter/pull/493)). [See release notes](https://github.com/Instabug/Instabug-iOS/releases/tag/13.3.0). + +### Deprecated + +- Deprecate Experiments APIs `Instabug.addExperiments`, `Instabug.removeExperiments` and `Instabug.clearAllExperiments` in favor of the new Feature Flags APIs ([#471](https://github.com/Instabug/Instabug-Flutter/pull/471)). + +### Fixed + +- Fix APM network logging on Android ([#491](https://github.com/Instabug/Instabug-Flutter/pull/491)). + ## [13.2.0](https://github.com/Instabug/Instabug-Flutter/compare/v13.1.1...v13.2.0) ### Added @@ -159,18 +178,18 @@ Below is a list of all the affected APIs: - - `APM.startExecutionTrace` - - `BugReporting.setOnInvokeCallback` - - `BugReporting.setOnDismissCallback` - - `Instabug.getTags` - - `Instabug.getUserAttributeForKey` - - `Instabug.getUserAttributes` - - `Replies.getUnreadRepliesCount` - - `Replies.hasChats` - - `Replies.setOnNewReplyReceivedCallback` - - `Surveys.hasRespondToSurvey` - - `Surveys.setOnShowCallback` - - `Surveys.setOnDismissCallback` + - `APM.startExecutionTrace` + - `BugReporting.setOnInvokeCallback` + - `BugReporting.setOnDismissCallback` + - `Instabug.getTags` + - `Instabug.getUserAttributeForKey` + - `Instabug.getUserAttributes` + - `Replies.getUnreadRepliesCount` + - `Replies.hasChats` + - `Replies.setOnNewReplyReceivedCallback` + - `Surveys.hasRespondToSurvey` + - `Surveys.setOnShowCallback` + - `Surveys.setOnDismissCallback` ## [11.12.0](https://github.com/Instabug/Instabug-Flutter/compare/v11.10.1...v11.12.0) (May 30, 2023) @@ -247,10 +266,10 @@ - Deprecates Instabug.enableAndroid and Instabug.disableAndroid APIs in favour of the new API Instabug.setEnabled, which works on both platforms - Deprecates callbacks in favor of return values in the following APIs: - 1. Replies.getUnreadRepliesCount - 2. Replies.hasChats - 3. Surveys.hasRespondedToSurvey - 4. Surveys.getAvailableSurveys + 1. Replies.getUnreadRepliesCount + 2. Replies.hasChats + 3. Surveys.hasRespondedToSurvey + 4. Surveys.getAvailableSurveys ## 11.3.0 (2022-09-30) diff --git a/android/build.gradle b/android/build.gradle index 38598f06b..f16d516e5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'com.instabug.flutter' -version '13.2.0' +version '13.3.0' buildscript { repositories { @@ -41,7 +41,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:13.2.0' + api 'com.instabug.library:instabug:13.3.0' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index ea14dc9e4..b28545745 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -14,6 +14,7 @@ import com.instabug.flutter.generated.ApmPigeon; import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; +import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import io.flutter.plugin.common.BinaryMessenger; @@ -210,9 +211,9 @@ public void networkLogAndroid(@NonNull Map data) { serverErrorMessage = (String) data.get("serverErrorMessage"); } - Method method = Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class); + Method method = Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class); if (method != null) { - method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage); + method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage, null); } else { Log.e(TAG, "APMNetworkLogger.log was not found by reflection"); } diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 12c0c72d6..74c4e4ba4 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -13,7 +13,14 @@ import com.instabug.flutter.util.ArgsRegistry; import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; -import com.instabug.library.*; +import com.instabug.library.Feature; +import com.instabug.library.Instabug; +import com.instabug.library.InstabugColorTheme; +import com.instabug.library.InstabugCustomTextPlaceHolder; +import com.instabug.library.IssueType; +import com.instabug.library.Platform; +import com.instabug.library.ReproConfigurations; +import com.instabug.library.featuresflags.model.IBGFeatureFlag; import com.instabug.library.internal.module.InstabugLocale; import com.instabug.library.invocation.InstabugInvocationEvent; import com.instabug.library.model.NetworkLog; @@ -28,6 +35,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -225,6 +233,37 @@ public void clearAllExperiments() { Instabug.clearAllExperiments(); } + @Override + public void addFeatureFlags(@NonNull Map featureFlags) { + try { + List features = new ArrayList<>(); + for (Map.Entry entry : featureFlags.entrySet()) { + features.add(new IBGFeatureFlag(entry.getKey(), entry.getValue().isEmpty() ? null : entry.getValue())); + } + Instabug.addFeatureFlags(features); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void removeFeatureFlags(@NonNull List featureFlags) { + try { + Instabug.removeFeatureFlag(featureFlags); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void removeAllFeatureFlags() { + try { + Instabug.removeAllFeatureFlags(); + } catch (Exception e) { + e.printStackTrace(); + } + } + @Override public void setUserAttribute(@NonNull String value, @NonNull String key) { Instabug.setUserAttribute(key, value); diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index 677da604b..935521466 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -262,7 +262,8 @@ public void testNetworkLogAndroid() { responseContentType, errorDomain, null, - serverErrorMessage + serverErrorMessage, + null )); mAPMNetworkLogger.close(); diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index deb8d7b47..2abb8987e 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -35,6 +35,7 @@ import com.instabug.library.Platform; import com.instabug.library.ReproConfigurations; import com.instabug.library.ReproMode; +import com.instabug.library.featuresflags.model.IBGFeatureFlag; import com.instabug.library.invocation.InstabugInvocationEvent; import com.instabug.library.model.NetworkLog; import com.instabug.library.ui.onboarding.WelcomeMessage; @@ -48,6 +49,7 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -345,6 +347,32 @@ public void testClearAllExperiments() { mInstabug.verify(Instabug::clearAllExperiments); } + @Test + public void testAddFeatureFlags() { + Map featureFlags = new HashMap<>(); + featureFlags.put("key1","variant1"); + api.addFeatureFlags(featureFlags); + List flags=new ArrayList(); + flags.add(new IBGFeatureFlag("key1","variant1")); + mInstabug.verify(() -> Instabug.addFeatureFlags(flags)); + } + + @Test + public void testRemoveFeatureFlags() { + List featureFlags = Arrays.asList("premium", "star"); + + api.removeFeatureFlags(featureFlags); + + mInstabug.verify(() -> Instabug.removeFeatureFlag(featureFlags)); + } + + @Test + public void testClearAllFeatureFlags() { + api.removeAllFeatureFlags(); + + mInstabug.verify(Instabug::removeAllFeatureFlags); + } + @Test public void testSetUserAttribute() { String key = "is_premium"; diff --git a/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java b/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java index c25d8f46e..0795acf77 100644 --- a/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java +++ b/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java @@ -8,6 +8,7 @@ import android.net.Uri; import android.util.Log; +import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import com.instabug.crash.models.IBGNonFatalException; import org.json.JSONObject; @@ -69,10 +70,10 @@ public static void setUp() throws NoSuchMethodException { .when(() -> Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "setCurrentPlatform", int.class)) .thenReturn(mSetCurrentPlatform); - Method mAPMNetworkLog = MockReflected.class.getDeclaredMethod("apmNetworkLog", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class); + Method mAPMNetworkLog = MockReflected.class.getDeclaredMethod("apmNetworkLog", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class); mAPMNetworkLog.setAccessible(true); reflection - .when(() -> Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class)) + .when(() -> Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class)) .thenReturn(mAPMNetworkLog); Method mCrashReportException = MockReflected.class.getDeclaredMethod("crashReportException", JSONObject.class, boolean.class); diff --git a/android/src/test/java/com/instabug/flutter/util/MockReflected.java b/android/src/test/java/com/instabug/flutter/util/MockReflected.java index 255664165..42c85664b 100644 --- a/android/src/test/java/com/instabug/flutter/util/MockReflected.java +++ b/android/src/test/java/com/instabug/flutter/util/MockReflected.java @@ -3,6 +3,7 @@ import android.graphics.Bitmap; import androidx.annotation.Nullable; +import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import com.instabug.crash.models.IBGNonFatalException; import org.json.JSONObject; @@ -33,7 +34,7 @@ public static void setCurrentPlatform(int platform) {} /** * APMNetworkLogger.log */ - public static void apmNetworkLog(long requestStartTime, long requestDuration, String requestHeaders, String requestBody, long requestBodySize, String requestMethod, String requestUrl, String responseHeaders, String responseBody, String responseBodySize, long statusCode, int responseContentType, String errorMessage, String var18, @Nullable String gqlQueryName, @Nullable String serverErrorMessage) {} + public static void apmNetworkLog(long requestStartTime, long requestDuration, String requestHeaders, String requestBody, long requestBodySize, String requestMethod, String requestUrl, String responseHeaders, String responseBody, String responseBodySize, long statusCode, int responseContentType, String errorMessage, String var18, @Nullable String gqlQueryName, @Nullable String serverErrorMessage, @Nullable APMCPNetworkLog.W3CExternalTraceAttributes w3CExternalTraceAttributes) {} /** * CrashReporting.reportException diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index 9f9684120..886e22ece 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -224,6 +224,46 @@ - (void)testClearAllExperiments { OCMVerify([self.mInstabug clearAllExperiments]); } +- (void)testAddFeatureFlags { + NSDictionary *featureFlagsMap = @{ @"key13" : @"value1", @"key2" : @"value2"}; + FlutterError *error; + + [self.api addFeatureFlagsFeatureFlagsMap:featureFlagsMap error:&error]; + OCMVerify([self.mInstabug addFeatureFlags: [OCMArg checkWithBlock:^(id value) { + NSArray *featureFlags = value; + NSString* firstFeatureFlagName = [featureFlags objectAtIndex:0 ].name; + NSString* firstFeatureFlagKey = [[featureFlagsMap allKeys] objectAtIndex:0] ; + if([ firstFeatureFlagKey isEqualToString: firstFeatureFlagName]){ + return YES; + } + return NO; + }]]); +} + +- (void)testRemoveFeatureFlags { + NSArray *featureFlags = @[@"exp1"]; + FlutterError *error; + + [self.api removeFeatureFlagsFeatureFlags:featureFlags error:&error]; + OCMVerify([self.mInstabug removeFeatureFlags: [OCMArg checkWithBlock:^(id value) { + NSArray *featureFlagsObJ = value; + NSString* firstFeatureFlagName = [featureFlagsObJ objectAtIndex:0 ].name; + NSString* firstFeatureFlagKey = [featureFlags firstObject] ; + if([ firstFeatureFlagKey isEqualToString: firstFeatureFlagName]){ + return YES; + } + return NO; + }]]);} + +- (void)testRemoveAllFeatureFlags { + FlutterError *error; + + [self.api removeAllFeatureFlagsWithError:&error]; + OCMVerify([self.mInstabug removeAllFeatureFlags]); +} + + + - (void)testSetUserAttribute { NSString *key = @"is_premium"; NSString *value = @"true"; diff --git a/example/ios/Podfile b/example/ios/Podfile index 34e2dd968..cdffbc5db 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '13.4' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a7bcc3007..17a3f845c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,9 +1,9 @@ PODS: - Flutter (1.0.0) - - Instabug (13.2.0) - - instabug_flutter (13.2.0): + - Instabug (13.3.0) + - instabug_flutter (13.3.0): - Flutter - - Instabug (= 13.2.0) + - Instabug (= 13.3.0) - OCMock (3.6) DEPENDENCIES: @@ -23,11 +23,11 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - Instabug: aee76898789d17c55b36c7fbaa697e443effe3b1 - instabug_flutter: 8fe63955937c73205d4e71667aea9d56ed8d921b + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Instabug: 4f26295103a330ec0236918359eef7ccaa74e2fa + instabug_flutter: 6be22be13b3dda72b293151d2c009952bb20b940 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: f809f4241ff3da61349081a141c44763598f2fbb +PODFILE CHECKSUM: 8f7552fd115ace1988c3db54a69e4a123c448f84 -COCOAPODS: 1.13.0 +COCOAPODS: 1.14.3 diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 283a09ecf..404d79cdd 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -19,6 +19,15 @@ class _MyHomePageState extends State { final primaryColorController = TextEditingController(); final screenNameController = TextEditingController(); + final featureFlagsController = TextEditingController(); + + @override + void dispose() { + featureFlagsController.dispose(); + screenNameController.dispose(); + primaryColorController.dispose(); + super.dispose(); + } void restartInstabug() { Instabug.setEnabled(false); @@ -325,7 +334,36 @@ class _MyHomePageState extends State { ), ], ), + SectionTitle('FeatureFlags'), + InstabugTextField( + controller: featureFlagsController, + label: 'Feature Flag name', + ), + InstabugButton( + onPressed: () => setFeatureFlag(), + text: 'SetFeatureFlag', + ), + InstabugButton( + onPressed: () => removeFeatureFlag(), + text: 'RemoveFeatureFlag', + ), + InstabugButton( + onPressed: () => removeAllFeatureFlags(), + text: 'RemoveAllFeatureFlags', + ), ], ); } + + setFeatureFlag() { + Instabug.addFeatureFlags([FeatureFlag(name: featureFlagsController.text)]); + } + + removeFeatureFlag() { + Instabug.removeFeatureFlags([featureFlagsController.text]); + } + + removeAllFeatureFlags() { + Instabug.clearAllFeatureFlags(); + } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 9a3737cc2..5b56a50f9 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" espresso: dependency: "direct dev" description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -115,7 +115,31 @@ packages: path: ".." relative: true source: path - version: "13.2.0" + version: "13.3.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -128,50 +152,50 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.12.0" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.4" process: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" sky_engine: dependency: transitive description: flutter @@ -189,18 +213,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -229,10 +253,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.0" typed_data: dependency: transitive description: @@ -253,26 +277,18 @@ packages: dependency: transitive description: name: vm_service - sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f - url: "https://pub.dev" - source: hosted - version: "11.7.1" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "14.2.1" webdriver: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=2.10.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index c6806c805..44f356685 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -318,5 +318,40 @@ - (void)willRedirectToStoreWithError:(FlutterError * _Nullable __autoreleasing * [Instabug willRedirectToAppStore]; } +- (void)addFeatureFlagsFeatureFlagsMap:(nonnull NSDictionary *)featureFlagsMap error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + NSMutableArray *featureFlags = [NSMutableArray array]; + for(id key in featureFlagsMap){ + NSString* variant =((NSString * )[featureFlagsMap objectForKey:key]); + if ([variant length]==0) { + [featureFlags addObject:[[IBGFeatureFlag alloc] initWithName:key]]; + } + else{ + [featureFlags addObject:[[IBGFeatureFlag alloc] initWithName:key variant:variant]]; + + } + } + [Instabug addFeatureFlags:featureFlags]; +} + + +- (void)removeAllFeatureFlagsWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + [Instabug removeAllFeatureFlags]; + +} + + +- (void)removeFeatureFlagsFeatureFlags:(nonnull NSArray *)featureFlags error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + + NSMutableArray *features = [NSMutableArray array]; + for(id item in featureFlags){ + [features addObject:[[IBGFeatureFlag alloc] initWithName:item]]; + } + @try { + [Instabug removeFeatureFlags:features]; + } @catch (NSException *exception) { + NSLog(@"%@", exception); + + } +} @end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 080fb367b..31f7d8782 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'instabug_flutter' - s.version = '13.2.0' + s.version = '13.3.0' s.summary = 'Flutter plugin for integrating the Instabug SDK.' s.author = 'Instabug' s.homepage = 'https://www.instabug.com/platforms/flutter' @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "Instabug"'} s.dependency 'Flutter' - s.dependency 'Instabug', '13.2.0' + s.dependency 'Instabug', '13.3.0' end diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index cfd50ce30..783fb1350 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -1,6 +1,7 @@ // Models export 'src/models/crash_data.dart'; export 'src/models/exception_data.dart'; +export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; export 'src/models/trace.dart'; // Modules diff --git a/lib/src/models/feature_flag.dart b/lib/src/models/feature_flag.dart new file mode 100644 index 000000000..2cd94fd67 --- /dev/null +++ b/lib/src/models/feature_flag.dart @@ -0,0 +1,9 @@ +class FeatureFlag { + /// the name of feature flag + String name; + + /// The variant of the feature flag. + String? variant; + + FeatureFlag({required this.name, this.variant}); +} diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index b0628f258..9d578e030 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -1,9 +1,11 @@ // ignore_for_file: avoid_classes_with_only_static_members import 'dart:async'; + // to maintain supported versions prior to Flutter 3.3 // ignore: unnecessary_import import 'dart:typed_data'; + // to maintain supported versions prior to Flutter 3.3 // ignore: unnecessary_import import 'dart:ui'; @@ -246,20 +248,50 @@ class Instabug { } /// Adds experiments to the next report. + @Deprecated( + 'Please migrate to the new feature flags APIs: Instabug.addFeatureFlags.', + ) static Future addExperiments(List experiments) async { return _host.addExperiments(experiments); } /// Removes certain experiments from the next report. + @Deprecated( + 'Please migrate to the new feature flags APIs: Instabug.removeFeatureFlags.', + ) static Future removeExperiments(List experiments) async { return _host.removeExperiments(experiments); } /// Clears all experiments from the next report. + + @Deprecated( + 'Please migrate to the new feature flags APIs: Instabug.clearAllFeatureFlags.', + ) static Future clearAllExperiments() async { return _host.clearAllExperiments(); } + /// Adds feature flags to the next report. + static Future addFeatureFlags(List featureFlags) async { + final map = {}; + for (final value in featureFlags) { + map[value.name] = value.variant ?? ''; + } + + return _host.addFeatureFlags(map); + } + + /// Removes certain feature flags from the next report. + static Future removeFeatureFlags(List featureFlags) async { + return _host.removeFeatureFlags(featureFlags); + } + + /// Clears all feature flags from the next report. + static Future clearAllFeatureFlags() async { + return _host.removeAllFeatureFlags(); + } + /// Add custom user attribute [value] with a [key] that is going to be sent with each feedback, bug or crash. static Future setUserAttribute(String value, String key) async { return _host.setUserAttribute(value, key); diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index 6da75bcaa..b839f8d1e 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -31,6 +31,9 @@ abstract class InstabugHostApi { void addExperiments(List experiments); void removeExperiments(List experiments); void clearAllExperiments(); + void addFeatureFlags(Map featureFlagsMap); + void removeFeatureFlags(List featureFlags); + void removeAllFeatureFlags(); void setUserAttribute(String value, String key); void removeUserAttribute(String key); diff --git a/pubspec.yaml b/pubspec.yaml index fcf86264f..76c665ab3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: instabug_flutter -version: 13.2.0 +version: 13.3.0 description: >- Instabug empowers mobile teams to monitor, prioritize, and debug performance and stability issues throughout the app development lifecycle. @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter lint: ^1.0.0 # mockito v5.2.0 is needed for running Flutter 2 tests on CI - mockito: '>=5.2.0 <=5.4.2' + mockito: '>=5.2.0 <5.5.0' pana: ^0.21.0 # pigeon v3.0.0 is needed for running Flutter 2 tests on CI pigeon: '>=3.0.0 <=10.1.5' diff --git a/test/instabug_test.dart b/test/instabug_test.dart index a6631859d..f525dc02c 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -239,6 +239,7 @@ void main() { test('[addExperiments] should call host method', () async { const experiments = ["exp-1", "exp-2"]; + // ignore: deprecated_member_use_from_same_package await Instabug.addExperiments(experiments); verify( @@ -249,6 +250,7 @@ void main() { test('[removeExperiments] should call host method', () async { const experiments = ["exp-1", "exp-2"]; + // ignore: deprecated_member_use_from_same_package await Instabug.removeExperiments(experiments); verify( @@ -257,6 +259,7 @@ void main() { }); test('[clearAllExperiments] should call host method', () async { + // ignore: deprecated_member_use_from_same_package await Instabug.clearAllExperiments(); verify( @@ -264,6 +267,38 @@ void main() { ).called(1); }); + test('[addFeatureFlags] should call host method', () async { + await Instabug.addFeatureFlags([ + FeatureFlag(name: 'name1', variant: 'variant1'), + FeatureFlag(name: 'name2', variant: 'variant2'), + ]); + + verify( + mHost.addFeatureFlags({ + "name1": "variant1", + "name2": "variant2", + }), + ).called(1); + }); + + test('[removeFeatureFlags] should call host method', () async { + const featureFlags = ["exp-1", "exp-2"]; + + await Instabug.removeFeatureFlags(featureFlags); + + verify( + mHost.removeFeatureFlags(featureFlags), + ).called(1); + }); + + test('[clearAllFeatureFlags] should call host method', () async { + await Instabug.clearAllFeatureFlags(); + + verify( + mHost.removeAllFeatureFlags(), + ).called(1); + }); + test('[setUserAttribute] should call host method', () async { const key = "attr-key"; const attribute = "User Attribute";