diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc3356e1..671138978 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Added +- Add support for persistent early crashes detection and reporting. ([#584](https://github.com/Instabug/Instabug-Flutter/pull/584)) + - Add support for xCode 16. ([#574](https://github.com/Instabug/Instabug-Flutter/pull/574)) - Add support for BugReporting user consents. ([#573](https://github.com/Instabug/Instabug-Flutter/pull/573)) 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 edfde055a..e9c6dea54 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -9,11 +9,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; + +import com.instabug.bug.BugReporting; import com.instabug.flutter.generated.InstabugPigeon; import com.instabug.flutter.util.ArgsRegistry; import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; -import com.instabug.library.ReproMode; import com.instabug.library.internal.crossplatform.CoreFeature; import com.instabug.library.internal.crossplatform.CoreFeaturesState; import com.instabug.library.internal.crossplatform.FeaturesStateListener; @@ -23,7 +24,6 @@ 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; @@ -68,20 +68,6 @@ public InstabugApi(Context context, Callable screenshotProvider, Instabu this.featureFlagsFlutterApi = featureFlagsFlutterApi; } - @VisibleForTesting - public void setCurrentPlatform() { - try { - Method method = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "setCurrentPlatform", int.class); - if (method != null) { - method.invoke(null, Platform.FLUTTER); - } else { - Log.e(TAG, "setCurrentPlatform was not found by reflection"); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - @Override public void setEnabled(@NonNull Boolean isEnabled) { try { @@ -106,8 +92,6 @@ public Boolean isEnabled() { @Override public void init(@NonNull String token, @NonNull List invocationEvents, @NonNull String debugLogsLevel) { - setCurrentPlatform(); - InstabugInvocationEvent[] invocationEventsArray = new InstabugInvocationEvent[invocationEvents.size()]; for (int i = 0; i < invocationEvents.size(); i++) { String key = invocationEvents.get(i); @@ -117,10 +101,15 @@ public void init(@NonNull String token, @NonNull List invocationEvents, final Application application = (Application) context; final int parsedLogLevel = ArgsRegistry.sdkLogLevels.get(debugLogsLevel); - new Instabug.Builder(application, token) - .setInvocationEvents(invocationEventsArray) - .setSdkDebugLogsLevel(parsedLogLevel) - .build(); + Log.i(TAG, "Instabug is built: " + Instabug.isBuilt()); + + if (Instabug.isBuilt()) { + Instabug.setSdkDebugLogsLevel(parsedLogLevel); + BugReporting.setInvocationEvents(invocationEventsArray); + } else { + InstabugInitializer.Builder builder = new InstabugInitializer.Builder(application, token, parsedLogLevel, invocationEventsArray); + builder.build(); + } Instabug.setScreenshotProvider(screenshotProvider); } diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugInitializer.java b/android/src/main/java/com/instabug/flutter/modules/InstabugInitializer.java new file mode 100644 index 000000000..af1660dc6 --- /dev/null +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugInitializer.java @@ -0,0 +1,95 @@ +package com.instabug.flutter.modules; + +import android.app.Application; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; + +import com.instabug.flutter.util.Reflection; +import com.instabug.library.Instabug; +import com.instabug.library.Platform; +import com.instabug.library.invocation.InstabugInvocationEvent; + +import java.lang.reflect.Method; + +public class InstabugInitializer { + private final String TAG = InstabugApi.class.getName(); + private static InstabugInitializer instance; + + private InstabugInitializer() {} + + public static InstabugInitializer getInstance() { + if (instance == null) { + synchronized (InstabugInitializer.class) { + if (instance == null) { + instance = new InstabugInitializer(); + } + } + } + return instance; + } + + @VisibleForTesting + public void setCurrentPlatform() { + try { + Method method = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "setCurrentPlatform", int.class); + if (method != null) { + method.invoke(null, Platform.FLUTTER); + } else { + Log.e(TAG, "setCurrentPlatform was not found by reflection"); + } + } catch (Exception e) { + Log.e(TAG, "Error setting current platform", e); + } + } + + public static class Builder { + /** + * Application instance to initialize Instabug. + */ + private Application application; + + /** + * The application token obtained from the Instabug dashboard. + */ + private String applicationToken; + + /** + * The level of detail in logs that you want to print. + */ + private int logLevel; + + /** + * The events that trigger the SDK's user interface. + */ + private InstabugInvocationEvent[] invocationEvents; + + /** + * Initialize Instabug SDK with application token and invocation trigger events + * + * @param application Application object for initialization of library + * @param applicationToken The app's identifying token, available on your dashboard. + * @param invocationEvents The events that trigger the SDK's user interface. + *

Choose from the available events listed in {@link InstabugInvocationEvent}.

+ */ + public Builder(Application application, String applicationToken, int logLevel, InstabugInvocationEvent... invocationEvents) { + this.application = application; + this.applicationToken = applicationToken; + this.logLevel = logLevel; + this.invocationEvents = invocationEvents; + } + + public void build() { + try { + InstabugInitializer.getInstance().setCurrentPlatform(); + + Instabug.Builder instabugBuilder = new Instabug.Builder(application, applicationToken, invocationEvents) + .setSdkDebugLogsLevel(logLevel); + + instabugBuilder.build(); + } catch (Exception e) { + Log.e(InstabugInitializer.instance.TAG, "Error building Instabug", e); + } + } + } +} \ No newline at end of file diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 97b9cdf7b..9046077f8 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -122,13 +122,6 @@ public void testInit() { mHostApi.verify(() -> InstabugPigeon.InstabugHostApi.setup(eq(messenger), any(InstabugApi.class))); } - @Test - public void testSetCurrentPlatform() { - api.setCurrentPlatform(); - - reflected.verify(() -> MockReflected.setCurrentPlatform(Platform.FLUTTER)); - } - @Test public void testSdkInit() { String token = "app-token"; @@ -153,7 +146,7 @@ public void testSdkInit() { 1, mInstabugBuilder.constructed().size() ); - verify(builder).setInvocationEvents(InstabugInvocationEvent.FLOATING_BUTTON); + verify(builder).setSdkDebugLogsLevel(LogLevel.ERROR); verify(builder).build(); diff --git a/android/src/test/java/com/instabug/flutter/InstabugInitializerTest.java b/android/src/test/java/com/instabug/flutter/InstabugInitializerTest.java new file mode 100644 index 000000000..1739b2e3f --- /dev/null +++ b/android/src/test/java/com/instabug/flutter/InstabugInitializerTest.java @@ -0,0 +1,47 @@ +package com.instabug.flutter; + +import static com.instabug.flutter.util.GlobalMocks.reflected; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; + +import com.instabug.flutter.modules.InstabugInitializer; +import com.instabug.flutter.util.GlobalMocks; +import com.instabug.flutter.util.MockReflected; +import com.instabug.library.Instabug; +import com.instabug.library.Platform; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockedStatic; + +import io.flutter.plugin.common.BinaryMessenger; + +public class InstabugInitializerTest { + private InstabugInitializer api; + private MockedStatic mInstabug; + + @Before + public void setUp() throws NoSuchMethodException { + + BinaryMessenger mMessenger = mock(BinaryMessenger.class); + api = spy(InstabugInitializer.getInstance()); + mInstabug = mockStatic(Instabug.class); + GlobalMocks.setUp(); + } + + @After + public void cleanUp() { + mInstabug.close(); + GlobalMocks.close(); + + } + + @Test + public void testSetCurrentPlatform() { + api.setCurrentPlatform(); + + reflected.verify(() -> MockReflected.setCurrentPlatform(Platform.FLUTTER)); + } +} diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 483f4dd2e..85eafba4e 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -25,6 +25,10 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> + +