Error while integrating Pendo for Flutter Android
Closed this issue · 10 comments
Platform + Version
Android 13
SDK Version
pendo_sdk: ^3.3.2
Framework
e.g Native, SwiftUI,
Flutter 3.24.0
Describe the bug
I got some errors while integrating Pendo for Android Flutter
Couldn't remove listener from GoRouter's nested branch
PendoScan: primaryFocusHash is 0, might cause issues with current scan
Retro Element Info NOT FOUND
To Reproduce
Steps to reproduce the behavior:
Check the sample code section
Expected behavior
No errors
Logs
PendoFlutterPlugin method name: setup
PendoFlutterPlugin method name: track
PendoFlutterPlugin method name: startSession
[Pendo] [20:28:02.394] ⛔ Couldn't remove listener from GoRouter's nested branch. Seems like the listener is different then the one added.
✅ Pendo Mobile SDK was successfully integrated and connected to the server.
You can start adding guides to your app in our web console.
App version identified: '1.1.25'
SDK version identified: '3.3.0.8585'
Plugin version identified: '3.3.2'
PendoFlutterPlugin method name: screenChanged
PendoFlutterPlugin method name: sendAction
PendoFlutterPlugin method name: sendAction
flutter: [Pendo] [20:28:45.303] ❗️ PendoScan: primaryFocusHash is 0, might cause issues with current scan
PendoFlutterPlugin method name: screenChanged
flutter: [Pendo] [20:28:45.353] ⛔ Retro Element Info NOT FOUND!
Sample Code
In main.dart
await PendoSDK.setDebugMode(isDebugEnabled: kDebugMode);
await PendoSDK.setup(pendoKey);
final String visitorId = await getDeviceIdentifier();
final Map<String, dynamic> visitorData = <String, dynamic>{
'Device Type': UniversalPlatform.operatingSystem,
};
final Map<String, dynamic> accountData = <String, dynamic>{};
await PendoSDK.startSession(
visitorId,
null,
visitorData,
accountData,
);
await PendoSDK.track(
'name',
<String, dynamic>{
'firstProperty': 'firstPropertyValue',
'secondProperty': 'secondPropertyValue',
},
);
and for app.dart
class _AppState extends State<App> {
static final NestedBranchesObserver _pendoGoRouterObserver =
NestedBranchesObserver(); // Pendo observer for the GoRouter
void _addRouterToPendoObserver() {
_pendoGoRouterObserver
..removeListener(router)
..addListener(router);
}
@override
void initState() {
super.initState();
_addRouterToPendoObserver(); // Add your GoRouter instance to the Pendo observer
}
@override
Future<void> dispose() async {
_pendoGoRouterObserver.removeListener(router);
super.dispose();
}
@override
Widget build(BuildContext context) => PendoActionListener(
child: KeyboardVisibilityProvider(
child: MaterialApp.router(
routerConfig: router,
and for go router
final GoRouter router = GoRouter(
// redirect is no longer needed to handle the deep links
observers: <NavigatorObserver>[
PendoNavigationObserver(),
],
Hi @amrgetment
Few things
⛔ Couldn't remove listener from GoRouter's nested branch. Seems like the listener is different then the one added.
please ignore it we are working on new (one line integration that will be much simpler then the current one and this logs will be removed)- If you are using GoRouter please remove
PendoNavigationObserver()
from the observers
we have explained it Flutter Integration ,( Now looking at it maybe our doc wasn't that clear, We will fix it with new integration.)
3. Important PendoScan: primaryFocusHash is 0, might cause issues with current scan PendoFlutterPlugin method name: screenChanged
that log is not so good
Few words of explanation:
In general we are scaning the area under the primary focus to get click analytics on the page.
By default, we are using primary focus as staring point for the scan of clickable elements and features for the analytics .
So first question why would primary focus will be null in your app?
(WidgetsBinding.instance.focusManager.primaryFocus
why would that be null?)
Do you use builder
callback in your Material app? (I have seen some issues with that callback and primary focus)
(as a side note: we are working on a new more precise and efficient way to scan the relevant route without the dependency on primary focus)
Thanks
@MikePendo Yes I have builder before Material.router
,
when do you expect to scan the relevant route without the dependency on primary focus?
@override
Widget build(BuildContext context) => PendoActionListener(
child: AppRepositoriesProvider(
child: AppBlocProvider(
child: Builder(
builder: (BuildContext context) => MultiBlocListener(
listeners: [ ],
child: ScreenUtilInit(
builder: (_, __) => KeyboardVisibilityProvider(
child: MaterialApp.router(
I followed proguard in the following guide for Android but I got the following error
https://github.com/pendo-io/pendo-mobile-sdk/blob/master/android/pnddocs/pendo-proguard.cfg
java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/navigation/NavController$OnDestinationChangedListener
Logs
```dart Launching lib/main.dart on Android SDK built for x86 in debug mode... ✓ Built build/app/outputs/flutter-apk/app-dev-debug.apk Connecting to VM Service at ws://127.0.0.1:65505/FUSy6rZYMdU=/ws Connected to the VM Service. I/zygote ( 6044): Rejecting re-init on previously-failed class java.lang.Class: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/navigation/NavController$OnDestinationChangedListener; I/zygote ( 6044): at sdk.pendo.io.f9.f sdk.pendo.io.f9.l.a(sdk.pendo.io.Pendo$PendoOptions$Framework, sdk.pendo.io.Pendo$PendoOptions) (SourceFile:-1) I/zygote ( 6044): at void sdk.pendo.io.PendoInternal.a(android.content.Context, java.lang.String, sdk.pendo.io.Pendo$PendoOptions, sdk.pendo.io.PendoPhasesCallbackInterface) (SourceFile:21) I/zygote ( 6044): at void sdk.pendo.io.Pendo.setup(android.content.Context, java.lang.String, sdk.pendo.io.Pendo$PendoOptions, sdk.pendo.io.PendoPhasesCallbackInterface) (SourceFile:-1) I/zygote ( 6044): at void pendo.io.pendo_sdk.PendoFlutterPlugin.setup(io.flutter.plugin.common.MethodCall, io.flutter.plugin.common.MethodChannel$Result) (PendoFlutterPlugin.java:280) I/zygote ( 6044): at void pendo.io.pendo_sdk.PendoFlutterPlugin.onMethodCall(io.flutter.plugin.common.MethodCall, io.flutter.plugin.common.MethodChannel$Result) (PendoFlutterPlugin.java:147) I/zygote ( 6044): at void io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(java.nio.ByteBuffer, io.flutter.plugin.common.BinaryMessenger$BinaryReply) (MethodChannel.java:267) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(io.flutter.embedding.engine.dart.DartMessenger$HandlerInfo, java.nio.ByteBuffer, int) (DartMessenger.java:292) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(java.lang.String, int, io.flutter.embedding.engine.dart.DartMessenger$HandlerInfo, java.nio.ByteBuffer, long) (DartMessenger.java:319) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run() (D8$$SyntheticClass:0) I/zygote ( 6044): at void android.os.Handler.handleCallback(android.os.Message) (Handler.java:790) I/zygote ( 6044): at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:99) I/zygote ( 6044): at void android.os.Looper.loop() (Looper.java:164) I/zygote ( 6044): at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6494) I/zygote ( 6044): at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2) I/zygote ( 6044): at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:438) I/zygote ( 6044): at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:807) I/zygote ( 6044): Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.navigation.NavController$OnDestinationChangedListener" on path: DexPathList[[zip file "/data/app/io.getme.app.dev-o4xmS8729ViNXWuZanFYnA==/base.apk"],nativeLibraryDirectories=[/data/app/io.getme.app.dev-o4xmS8729ViNXWuZanFYnA==/lib/x86, /data/app/io.getme.app.dev-o4xmS8729ViNXWuZanFYnA==/base.apk!/lib/x86, /system/lib, /vendor/lib]] I/zygote ( 6044): at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:125) I/zygote ( 6044): at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379) I/zygote ( 6044): at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312) I/zygote ( 6044): at sdk.pendo.io.f9.f sdk.pendo.io.f9.l.a(sdk.pendo.io.Pendo$PendoOptions$Framework, sdk.pendo.io.Pendo$PendoOptions) (SourceFile:-1) I/zygote ( 6044): at void sdk.pendo.io.PendoInternal.a(android.content.Context, java.lang.String, sdk.pendo.io.Pendo$PendoOptions, sdk.pendo.io.PendoPhasesCallbackInterface) (SourceFile:21) I/zygote ( 6044): at void sdk.pendo.io.Pendo.setup(android.content.Context, java.lang.String, sdk.pendo.io.Pendo$PendoOptions, sdk.pendo.io.PendoPhasesCallbackInterface) (SourceFile:-1) I/zygote ( 6044): at void pendo.io.pendo_sdk.PendoFlutterPlugin.setup(io.flutter.plugin.common.MethodCall, io.flutter.plugin.common.MethodChannel$Result) (PendoFlutterPlugin.java:280) I/zygote ( 6044): at void pendo.io.pendo_sdk.PendoFlutterPlugin.onMethodCall(io.flutter.plugin.common.MethodCall, io.flutter.plugin.common.MethodChannel$Result) (PendoFlutterPlugin.java:147) I/zygote ( 6044): at void io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(java.nio.ByteBuffer, io.flutter.plugin.common.BinaryMessenger$BinaryReply) (MethodChannel.java:267) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(io.flutter.embedding.engine.dart.DartMessenger$HandlerInfo, java.nio.ByteBuffer, int) (DartMessenger.java:292) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(java.lang.String, int, io.flutter.embedding.engine.dart.DartMessenger$HandlerInfo, java.nio.ByteBuffer, long) (DartMessenger.java:319) I/zygote ( 6044): at void io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run() (D8$$SyntheticClass:0) I/zygote ( 6044): at void android.os.Handler.handleCallback(android.os.Message) (Handler.java:790) I/zygote ( 6044): at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:99) I/zygote ( 6044): at void android.os.Looper.loop() (Looper.java:164) I/zygote ( 6044): at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6494) I/zygote ( 6044): at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2) I/zygote ( 6044): at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:438) I/zygote ( 6044): at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:807) I/zygote ( 6044):</details>
@amrgetment, we are checking the issue you have with a proguard... Please tell us as more details as possible:
- Does your app is a pure Flutter app or you have some parts implemented in the native code as well?
- Which installation instructions you've followed?
- What is your
android/app/bulid.gradle
dependencies and their versions? - What is your
android/app/bulid.gradle
configurations? - Send us your dependency tree
Thanks.
@amrgetment
We are working to avoid that dependency on primaryFocus. I really hope we will be bale to do it in 3.4.
I saw that issue for one client in the builder
of MaterialApp
do you use that builder.
@MikePendo Yes I need that builder to pass the context from the blocs to the child
AppRepositoriesProvider(
child: AppBlocProvider(
child: Builder(
builder: (BuildContext context) =>
otherwise, I will get an error
Error: Could not find the correct Provider<ThemeBloc> above this App Widget
I will wait next release 3.4 or 3.5 if possible
Thanks for your efforts
@DavidPendo I found that the proguard issue happened for Android API 27 or less but not on API 29, so it is not an issue for me as I have min SDK API 29
Any expectation for when 3.4 will be released
mid September, that will be the GA
We have a design partner program, in that case we can provide you with a beta build much earlier
@amrgetment
maybe you can share some insight why would you primary focus might be null
WidgetsBinding.instance.focusManager.primaryFocus
why the following might be null in your app?
I don't know the reason but it is nullable anyway
FocusNode? get primaryFocus => _primaryFocus;
https://api.flutter.dev/flutter/widgets/FocusManager/primaryFocus.html
Yes, I ok with joining the partner program to test the beta for you