Skip to content

Commit f408c8a

Browse files
Merge pull request #627 from Instabug/feat/screen-render-android-back-btn
Feat/screen render android back btn
2 parents 2a3a72c + 19226b1 commit f408c8a

File tree

14 files changed

+168
-49
lines changed

14 files changed

+168
-49
lines changed

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ android {
5252
}
5353

5454
dependencies {
55-
api 'com.instabug.library:instabug:15.0.2.7160278-SNAPSHOT'
55+
api 'com.instabug.library:instabug:16.0.0.6893269-SNAPSHOT'
5656
testImplementation 'junit:junit:4.13.2'
5757
testImplementation "org.mockito:mockito-inline:3.12.1"
5858
testImplementation "io.mockk:mockk:1.13.13"

android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111

1212
import androidx.annotation.NonNull;
1313
import androidx.annotation.Nullable;
14+
import androidx.lifecycle.Lifecycle;
15+
import androidx.lifecycle.LifecycleEventObserver;
16+
import androidx.lifecycle.LifecycleOwner;
1417

18+
import com.instabug.flutter.generated.InstabugPigeon;
1519
import com.instabug.flutter.modules.ApmApi;
1620
import com.instabug.flutter.modules.BugReportingApi;
1721
import com.instabug.flutter.modules.CrashReportingApi;
@@ -27,19 +31,23 @@
2731
import io.flutter.embedding.engine.plugins.FlutterPlugin;
2832
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
2933
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
34+
import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference;
3035
import io.flutter.embedding.engine.renderer.FlutterRenderer;
3136
import io.flutter.plugin.common.BinaryMessenger;
3237

33-
public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware {
38+
public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware, LifecycleEventObserver {
3439
private static final String TAG = InstabugFlutterPlugin.class.getName();
3540

3641
@SuppressLint("StaticFieldLeak")
3742
private static Activity activity;
3843

44+
private InstabugPigeon.InstabugFlutterApi instabugFlutterApi;
45+
private Lifecycle lifecycle;
3946

4047
@Override
4148
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
4249
register(binding.getApplicationContext(), binding.getBinaryMessenger(), (FlutterRenderer) binding.getTextureRegistry());
50+
instabugFlutterApi = new InstabugPigeon.InstabugFlutterApi(binding.getBinaryMessenger());
4351
}
4452

4553
@Override
@@ -50,23 +58,60 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
5058
@Override
5159
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
5260
activity = binding.getActivity();
61+
62+
// Register lifecycle observer if available
63+
if (binding.getLifecycle() instanceof HiddenLifecycleReference) {
64+
lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle();
65+
lifecycle.addObserver(this);
66+
}
5367
}
5468

5569
@Override
5670
public void onDetachedFromActivityForConfigChanges() {
71+
if (lifecycle != null) {
72+
lifecycle.removeObserver(this);
73+
}
5774
activity = null;
5875
}
5976

6077
@Override
6178
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
6279
activity = binding.getActivity();
80+
81+
// Re-register lifecycle observer if available
82+
if (binding.getLifecycle() instanceof HiddenLifecycleReference) {
83+
lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle();
84+
lifecycle.addObserver(this);
85+
}
6386
}
6487

6588
@Override
6689
public void onDetachedFromActivity() {
90+
if (lifecycle != null) {
91+
lifecycle.removeObserver(this);
92+
lifecycle = null;
93+
}
6794
activity = null;
6895
}
6996

97+
@Override
98+
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
99+
if (event == Lifecycle.Event.ON_PAUSE) {
100+
handleOnPause();
101+
}
102+
}
103+
104+
private void handleOnPause() {
105+
if (instabugFlutterApi != null) {
106+
instabugFlutterApi.dispose(new InstabugPigeon.InstabugFlutterApi.Reply<Void>() {
107+
@Override
108+
public void reply(Void reply) {
109+
Log.d(TAG, "Screen render cleanup dispose called successfully");
110+
}
111+
});
112+
}
113+
}
114+
70115
private static void register(Context context, BinaryMessenger messenger, FlutterRenderer renderer) {
71116
final Callable<Bitmap> screenshotProvider = new Callable<Bitmap>() {
72117
@Override
@@ -77,7 +122,7 @@ public Bitmap call() {
77122

78123
Callable<Float> refreshRateProvider = new Callable<Float>() {
79124
@Override
80-
public Float call(){
125+
public Float call() {
81126
return getRefreshRate();
82127
}
83128
};

android/src/main/java/com/instabug/flutter/modules/ApmApi.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,6 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) {
9393
}
9494
}
9595

96-
/**
97-
* Starts an execution trace and handles the result
98-
* using callbacks.
99-
*
100-
* @param id The `id` parameter is a non-null String that represents the identifier of the execution
101-
* trace.
102-
* @param name The `name` parameter in the `startExecutionTrace` method represents the name of the
103-
* execution trace that will be started. It is used as a reference to identify the trace during
104-
* execution monitoring.
105-
* @param result The `result` parameter in the `startExecutionTrace` method is an instance of
106-
* `ApmPigeon.Result<String>`. This parameter is used to provide the result of the execution trace
107-
* operation back to the caller. The `success` method of the `result` object is called with the
108-
*
109-
* @deprecated see {@link #startFlow}
110-
*/
111-
112-
11396
/**
11497
* Starts an AppFlow with the specified name.
11598
* <br/>

example/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ target 'Runner' do
3030

3131
use_frameworks!
3232
use_modular_headers!
33-
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec'
33+
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec'
3434
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
3535
end
3636

example/ios/Podfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
PODS:
22
- Flutter (1.0.0)
3-
- Instabug (15.1.31)
3+
- Instabug (15.1.32)
44
- instabug_flutter (14.3.0):
55
- Flutter
6-
- Instabug (= 15.1.31)
6+
- Instabug (= 15.1.32)
77
- OCMock (3.6)
88

99
DEPENDENCIES:
1010
- Flutter (from `Flutter`)
11-
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec`)
11+
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec`)
1212
- instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`)
1313
- OCMock (= 3.6)
1414

@@ -20,16 +20,16 @@ EXTERNAL SOURCES:
2020
Flutter:
2121
:path: Flutter
2222
Instabug:
23-
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec
23+
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec
2424
instabug_flutter:
2525
:path: ".symlinks/plugins/instabug_flutter/ios"
2626

2727
SPEC CHECKSUMS:
2828
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
29-
Instabug: 447d3f5a9f1c83120235437e08c9a51aaa8f8605
30-
instabug_flutter: 65aa2dee3036a3c7c8feff8e898c9547239a891d
29+
Instabug: ee379b2694fa1dd3951526e5a34782bac886102e
30+
instabug_flutter: 33230b1cc57be3b343b4d30f6dfdd03f9bf43599
3131
OCMock: 5ea90566be239f179ba766fd9fbae5885040b992
3232

33-
PODFILE CHECKSUM: c5b98f57c27da87950775c360d20aaedd3216b8d
33+
PODFILE CHECKSUM: 41b206566c390a4111f60619beb4e420eba98359
3434

3535
COCOAPODS: 1.15.2

example/lib/main.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void main() {
4747
appVariant: 'variant 1',
4848
);
4949
APM.setScreenRenderingEnabled(true);
50-
APM.setAutoUITraceEnabled(false);
50+
// APM.setAutoUITraceEnabled(false);
5151
FlutterError.onError = (FlutterErrorDetails details) {
5252
Zone.current.handleUncaughtError(details.exception, details.stack!);
5353
};

ios/instabug_flutter.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ Pod::Spec.new do |s|
1717
s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'}
1818

1919
s.dependency 'Flutter'
20-
s.dependency 'Instabug', '15.1.31'
20+
s.dependency 'Instabug', '15.1.32'
2121
end
2222

lib/src/modules/apm.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// ignore_for_file: avoid_classes_with_only_static_members
22

33
import 'dart:async';
4-
import 'dart:developer';
54

65
import 'package:flutter/widgets.dart' show WidgetBuilder;
76
import 'package:instabug_flutter/src/generated/apm.api.g.dart';
@@ -141,7 +140,6 @@ class APM {
141140
static Future<void> startUITrace(String name) async {
142141
final isScreenRenderingEnabled =
143142
await FlagsConfig.screenRendering.isEnabled();
144-
log("startUITrace: isScreenRenderEnabled: $isScreenRenderingEnabled");
145143
await InstabugScreenRenderManager.I
146144
.checkForScreenRenderInitialization(isScreenRenderingEnabled);
147145

lib/src/modules/instabug.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'package:instabug_flutter/src/utils/feature_flags_manager.dart';
2222
import 'package:instabug_flutter/src/utils/ibg_build_info.dart';
2323
import 'package:instabug_flutter/src/utils/instabug_logger.dart';
2424
import 'package:instabug_flutter/src/utils/screen_name_masker.dart';
25+
import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart';
2526
import 'package:meta/meta.dart';
2627

2728
enum InvocationEvent {
@@ -136,6 +137,23 @@ enum CustomTextPlaceHolderKey {
136137

137138
enum ReproStepsMode { enabled, disabled, enabledWithNoScreenshots }
138139

140+
/// Disposal manager for handling Android lifecycle events
141+
class _InstabugDisposalManager implements InstabugFlutterApi {
142+
_InstabugDisposalManager._();
143+
144+
static final _InstabugDisposalManager _instance =
145+
_InstabugDisposalManager._();
146+
147+
static _InstabugDisposalManager get instance => _instance;
148+
149+
@override
150+
void dispose() {
151+
// Call the InstabugWidgetsBindingObserver dispose method when Android onPause is triggered
152+
// to overcome calling onActivityDestroy() from android side before sending the data to it.
153+
InstabugWidgetsBindingObserver.dispose();
154+
}
155+
}
156+
139157
class Instabug {
140158
static var _host = InstabugHostApi();
141159

@@ -154,6 +172,8 @@ class Instabug {
154172
BugReporting.$setup();
155173
Replies.$setup();
156174
Surveys.$setup();
175+
// Set up InstabugFlutterApi for Android onDestroy disposal
176+
InstabugFlutterApi.setup(_InstabugDisposalManager.instance);
157177
}
158178

159179
/// @nodoc

lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'package:flutter/widgets.dart';
2+
import 'package:instabug_flutter/src/utils/ibg_build_info.dart';
23
import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart';
34
import 'package:instabug_flutter/src/utils/screen_name_masker.dart';
45
import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart';
6+
import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart';
57
import 'package:meta/meta.dart';
68

79
class InstabugWidgetsBindingObserver extends WidgetsBindingObserver {
@@ -19,41 +21,58 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver {
1921
/// Logging tag for debugging purposes.
2022
static const tag = "InstabugWidgetsBindingObserver";
2123

24+
/// Disposes all screen render resources.
2225
static void dispose() {
23-
// Always call dispose to ensure proper cleanup with tracking flags
26+
//Save the screen rendering data for the active traces Auto|Custom.
27+
InstabugScreenRenderManager.I.stopScreenRenderCollector();
28+
2429
// The dispose method is safe to call multiple times due to state tracking
2530
InstabugScreenRenderManager.I.dispose();
2631
}
2732

2833
void _handleResumedState() {
2934
final lastUiTrace = ScreenLoadingManager.I.currentUiTrace;
30-
if (lastUiTrace == null) {
31-
return;
32-
}
35+
36+
if (lastUiTrace == null) return;
37+
3338
final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName);
39+
3440
ScreenLoadingManager.I
3541
.startUiTrace(maskedScreenName, lastUiTrace.screenName)
36-
.then((uiTraceId) {
37-
if (uiTraceId != null &&
38-
InstabugScreenRenderManager.I.screenRenderEnabled) {
39-
//End any active ScreenRenderCollector before starting a new one (Safe garde condition).
40-
InstabugScreenRenderManager.I.endScreenRenderCollector();
41-
42-
//Start new ScreenRenderCollector.
43-
InstabugScreenRenderManager.I
44-
.startScreenRenderCollectorForTraceId(uiTraceId);
45-
}
42+
.then((uiTraceId) async {
43+
if (uiTraceId == null) return;
44+
45+
final isScreenRenderEnabled =
46+
await FlagsConfig.screenRendering.isEnabled();
47+
48+
if (!isScreenRenderEnabled) return;
49+
50+
await InstabugScreenRenderManager.I
51+
.checkForScreenRenderInitialization(isScreenRenderEnabled);
52+
53+
//End any active ScreenRenderCollector before starting a new one (Safe garde condition).
54+
InstabugScreenRenderManager.I.endScreenRenderCollector();
55+
56+
//Start new ScreenRenderCollector.
57+
InstabugScreenRenderManager.I
58+
.startScreenRenderCollectorForTraceId(uiTraceId);
4659
});
4760
}
4861

4962
void _handlePausedState() {
50-
if (InstabugScreenRenderManager.I.screenRenderEnabled) {
63+
// Only handles iOS platform because in android we use pigeon @FlutterApi().
64+
// To overcome the onActivityDestroy() before sending the data to the android side.
65+
if (InstabugScreenRenderManager.I.screenRenderEnabled &&
66+
IBGBuildInfo.I.isIOS) {
5167
InstabugScreenRenderManager.I.stopScreenRenderCollector();
5268
}
5369
}
5470

5571
Future<void> _handleDetachedState() async {
56-
if (InstabugScreenRenderManager.I.screenRenderEnabled) {
72+
// Only handles iOS platform because in android we use pigeon @FlutterApi().
73+
// To overcome the onActivityDestroy() before sending the data to the android side.
74+
if (InstabugScreenRenderManager.I.screenRenderEnabled &&
75+
IBGBuildInfo.I.isIOS) {
5776
dispose();
5877
}
5978
}

0 commit comments

Comments
 (0)