pendo-io/pendo-mobile-sdk

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

  1. Couldn't remove listener from GoRouter's nested branch
  2. PendoScan: primaryFocusHash is 0, might cause issues with current scan
  3. 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

  1. ⛔ 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)
  2. 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