ZEGOCLOUD/zego_uikit_prebuilt_call_flutter

The application does not go to the call (error: 'pageManager != null': pageManager is null)

Closed this issue · 3 comments

Hello!

I came across a problem for which I couldn't find a solution anywhere. I connected the package based on the information described in the documentation.

I would like to receive your help. Thank you in advance.

Environment

Technology Version
Flutter version 3.19.5
Plugin version zego_uikit_prebuilt_call: 4.9.0, zego_uikit_signaling_plugin: 2.7.6
Android version API 34
iOS version Not tested
macOS version Not tested
Xcode version Not tested
Google Chrome version Not tested

Device information:

I tried package on: real device pixel 7 with api 34; emulator pixel with api 34.

Description

Expected behavior:
Opening the call screen on the device; request an incoming call on another device.

Current behavior:
Nothing happens in the UI. The log contains the following error:


'package:zego_uikit_prebuilt_call/src/invitation/internal/internal_instance.dart': Failed assertion: line 21 pos 12: '_pageManager != null': pageManager is null, plugins call ZegoUIKitPrebuiltCallInvitationService().init(...) when user login

Steps to reproduce

  1. Wrote a service for calls (just divided into modules).

This service includes the implementation of interceptors for different events from the package side and some description of the custom UI.

videocalls_service.dart

import 'package:app_name/custom_code/custom_lib/features/videocalls/src/actions/on_call_end_action.dart';
import 'package:app_name/custom_code/custom_lib/features/videocalls/src/actions/on_outgoing_call_declined_action.dart';
import 'package:app_name/custom_code/custom_lib/features/videocalls/src/widgets/videocall_lobby/videocall_lobby_widget.dart';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:zego_uikit_prebuilt_call/zego_uikit_prebuilt_call.dart';
import 'package:zego_uikit_signaling_plugin/zego_uikit_signaling_plugin.dart';
import '../actions/on_error_action.dart';
import '../actions/on_outgoing_call_accepted_action.dart';
import '../actions/on_outgoing_call_rejected_cause_busy_action.dart';
import '../actions/on_outgoing_call_timeout_action.dart';
import '../constants/videocalls_constants.dart';
import '../models/video_call_duration_model.dart';
import '../utils/get_doc_ref_by_doc_id.dart';
import '../actions/on_hang_up_confirmation_action.dart';
import '../widgets/CustomZegoCallBottomBar/custom_zego_call_bottom_bar_widget.dart';

class VideocallsService {
  late final GlobalKey<NavigatorState> globalCallNavigatorKey;
  String? _userID;

  late final VideoCallDurationModel _videoCallDurationModel;

  VideoCallDurationModel get videoCallDurationModel => _videoCallDurationModel;

  VideocallsService({
    required GlobalKey<NavigatorState> navigatorKey,
  }) {
    globalCallNavigatorKey = navigatorKey;
    debugPrint(
      "-- VideocallsService -- init",
    );

    _videoCallDurationModel =
        VideoCallDurationModel(const Duration(seconds: 0));

    /// initialized ZegoUIKitPrebuiltCallInvitationService
  }

  Future<void> onSetup() async {
    try {
      debugPrint("-- VideocallsService -- onSetup");
      ZegoUIKitPrebuiltCallInvitationService()
          .setNavigatorKey(globalCallNavigatorKey);
      await ZegoUIKit().initLog();
      ZegoUIKitPrebuiltCallInvitationService().useSystemCallingUI(
        [ZegoUIKitSignalingPlugin()],
      );
    } catch (e) {
      debugPrint("-- VideocallsService -- onSetup - error: $e");
    }
  }

  void onUserLogin({
    required String userID,
    required String userName,
  }) {
    debugPrint("-- VideocallsService -- init");
    if (ZegoUIKitPrebuiltCallInvitationService().isInit) {
      return;
    }

    _userID = userID;

    _videoCallDurationModel =
        VideoCallDurationModel(const Duration(seconds: 0));

    /// initialized ZegoUIKitPrebuiltCallInvitationService
    /// when app's user is logged in or re-logged in
    /// We recommend calling this method as soon as the user logs in to your app.
    ZegoUIKitPrebuiltCallInvitationService().init(
      appID: VideocallsConstants.kAppID /*input your AppID*/,
      appSign: VideocallsConstants.kAppSign /*input your AppSign*/,
      userID: _userID!,
      userName: userName,
      plugins: [
        ZegoUIKitSignalingPlugin(),
      ],
      notificationConfig: ZegoCallInvitationNotificationConfig(
        androidNotificationConfig: ZegoCallAndroidNotificationConfig(
          showFullScreen: true,
        ),
      ),
      requireConfig: (ZegoCallInvitationData data) {
        final config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall();
        config.video = ZegoUIKitVideoConfig.preset540P();

        // Modify your custom configurations here.

        config.duration = ZegoCallDurationConfig(
          // isVisible: true,
          isVisible: false,
          onDurationUpdate: (Duration duration) {
            _videoCallDurationModel.update(duration);
            if (duration.inSeconds >=
                VideocallsConstants.kHangUpCallAfterInSeconds) {
              ZegoUIKitPrebuiltCallController()
                  .hangUp(globalCallNavigatorKey.currentState!.context);
            }
          },
        );

        config.layout = ZegoLayout.pictureInPicture(
          smallViewSize: const Size(120, 90),
        );

        // Custom handlers

        config.layout = ZegoLayout.pictureInPicture(
          showNewScreenSharingViewInFullscreenMode: false,
        );
        config.topMenuBar = ZegoCallTopMenuBarConfig(
          isVisible: false,
        );
        // todo: maybe use standard realization
        config.bottomMenuBar = ZegoCallBottomMenuBarConfig(
          backgroundColor: Colors.white,
          hideAutomatically: false,
          hideByClick: false,
          buttons: List.empty(), 
        );

        config.foreground = CustomZegoCallBottomBar(
          userID: _userID!,
          globalCallNavigatorKey: globalCallNavigatorKey,
        );

        return config;
      },
      uiConfig: ZegoCallInvitationUIConfig(
        prebuiltWithSafeArea: false,
        declineButton: ZegoCallButtonUIConfig(
          visible: false,
        ),
        acceptButton: ZegoCallButtonUIConfig(
          visible: false,
        ),
        cancelButton: ZegoCallButtonUIConfig(
          visible: false,
        ),
        callingBackgroundBuilder: (context, size, info) {
          final callerRef = getDocRefByDocId(info.inviter.id, 'users');

          debugPrint(
              '-- ZegoUIKitPrebuiltCallInvitationService -- callingBackgroundBuilder: ${callerRef.id}');

          return VideocallLobbyWidget(
            userRef: callerRef,
            acceptButtonCallback: () =>
                ZegoUIKitPrebuiltCallInvitationService().accept(),
            declineButtonCallback: () =>
                ZegoUIKitPrebuiltCallInvitationService().reject(),
            isIncomingCall: callerRef != getDocRefByDocId(_userID!, 'users'),
          );
        },
      ),
      events: ZegoUIKitPrebuiltCallEvents(
        onError: (ZegoUIKitError error) {
          debugPrint(
              '-- ZegoUIKitPrebuiltCallEvents -- onError: ${error.toString()}');
        },
        onHangUpConfirmation: (event, onHangUpConfirmation) async {
          final result = await onHangUpConfirmationAction(
            event.context,
          );
          return result;
        },
        onCallEnd: (event, onCallEnd) async {
          await onCallEndAction(
            getDocRefByDocId(_userID!, 'users'),
          );

          // todo: maybe navigate to another screen
        },
      ),
      invitationEvents: ZegoUIKitPrebuiltCallInvitationEvents(
        onOutgoingCallTimeout: (callID, callees, isVideoCall) async {
          await onOutgoingCallTimeoutAction(
            context: globalCallNavigatorKey.currentState!.context,
            callID: callID,
            calleeUser: callees.first,
            customData: isVideoCall ? 'true' : 'false',
          );
        },
        onOutgoingCallRejectedCauseBusy: (callID, callee, customData) async {
          await onOutgoingCallRejectedCauseBusyAction(
            context: globalCallNavigatorKey.currentState!.context,
            callID: callID,
            calleeUser: callee,
            customData: customData,
          );
        },
        onOutgoingCallDeclined: (callID, callee, customData) async {
          await onOutgoingCallDeclinedAction(
            context: globalCallNavigatorKey.currentState!.context,
            callID: callID,
            calleeUser: callee,
            customData: customData,
          );
        },
        onError: (error) async {
          debugPrint(
            '-- ZegoUIKitPrebuiltCallInvitationEvents -- onError: ${error.toString()}',
          );
          await onErrorAction(
            context: globalCallNavigatorKey.currentState!.context,
            error: error,
          );
        },
        onOutgoingCallAccepted: (callID, callee) async {
          await onOutgoingCallAcceptedAction(
            getDocRefByDocId(_userID!, 'users'),
          );
        },
      ),
    );
  }

  /// on App's user logout
  void onUserLogout() {
    debugPrint("-- VideocallsService -- onUserLogout");
    ZegoUIKitPrebuiltCallInvitationService().uninit();
  }

  /// call user
  /// show loader in UI
  Future<void> sendCallInvite({
    required String calleeId,
    String? caleeName,
  }) async {
    final invitees = [
      ZegoCallUser(
        calleeId,
        caleeName ?? 'User',
      ),
    ];

    await ZegoUIKitPrebuiltCallInvitationService().send(
      invitees: invitees,
      isVideoCall: true,
      resourceID: 'zego_call',
    );
  }
}

  1. Connected the service with libraries
main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  GoRouter.optionURLReflectsImperativeAPIs = true;
  usePathUrlStrategy();
  await initFirebase();

  // Start initial custom actions code
  await actions.setOnlyPortraitOrientations();

  final globalCallNavigatorKey = GlobalKey<NavigatorState>();

  await dependenciesManager(
    globalCallNavigatorKey,
  );

  await actions.extraLoginHandler();
 /// other code

  final videocallsService = GetIt.I.get<VideocallsService>();
  await videocallsService.onSetup();
  
 /// other code

  runApp(ChangeNotifierProvider(
    create: (context) => appState,
    child: const MyApp(),
  ));
}

/// other code

class _MyAppState extends State<MyApp> {

 @override
  void initState() {
    final videocallsService = GetIt.I.get<VideocallsService>();

   /// other code
  
  // add in navigatorKey in GoRouter
    _router = createRouter(
      _appStateNotifier,
      videocallsService.globalCallNavigatorKey,
    );
   /// other code
 }

@override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'MazeVideoTinder',
      localizationsDelegates: const [
        FFLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      locale: _locale,
      supportedLocales: const [
        Locale('en'),
        Locale('ru'),
      ],
      theme: ThemeData(
        brightness: Brightness.light,
      ),
      themeMode: _themeMode,
      routerConfig: _router,
    );
  }
}

  1. When an autologin or login is made into the application, the method is called
extra_login_handler.dart

 Future<void> extraLoginHandler() async {
  try {
    final currentUser = await firebase_auth.FirebaseAuth.instance.currentUser;
  
    if (currentUser == null) {
      return;
    }
    debugPrint('-- extraLoginHandler - currentUser?.uid: ${currentUser?.uid}');
   
   /// other code

    final videocallsService = GetIt.I.get<VideocallsService>();
    videocallsService.onUserLogin(
      userID: currentUser.uid,
      userName: currentUser.displayName ?? 'Unnamed user',
    );
  } catch (e) {
    debugPrint('-- extraLoginHandler');
  }
}

  1. When i need to call to another user i call the following method:
start_call.dart

import 'package:app_name/custom_code/custom_lib/features/videocalls/src/services/videocalls_service.dart';
import 'package:get_it/get_it.dart';

Future<void> startCall(
  DocumentReference calleeRef,
  String calleeName,
) async {
  try {
    debugPrint('-- startCall - calleeRef: $calleeRef');
    final videocallsService = GetIt.I.get<VideocallsService>();
    await videocallsService.sendCallInvite(
      calleeId: calleeRef.id,
      caleeName: calleeName,
    );
  } catch (e) {
    debugPrint('-- startCall: $e');
  }
}

yoer commented

This is because you haven't executed ZegoUIKitPrebuiltCallInvitationService.init before call, or you executed ZegoUIKitPrebuiltCallInvitationService.uninit it after calling init.

You can try to debug by yourself to see if the assignment is normal (whether the ZegoCallInvitationInternalInstance.registe function is executed and the ZegoCallInvitationInternalInstance.unregiste function is not executed, ZegoCallInvitationInternalInstance is in zego_uikit_prebuilt_call/lib/src/invitation/internal/internal_instance.dart)

You can send the log over to have a look. The log directory is at /sdcard/Android/data/${your_bundle_id}/files/zego_prebuilt/uikit/Logs

I found out the following in the logs directory:

06052024.log

{call}  {call invitation service(245149572)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:25:28}  {INFO}
{call}  {call invitation service(245149572)}  {register background message handler}  {06/05/2024 07:25:28}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:25:28}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:25:28}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:25:28}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:25:29}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:25:29}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:25:29}  {INFO}
{call}  {call invitation service(664652913)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:33:36}  {INFO}
{call}  {call invitation service(664652913)}  {register background message handler}  {06/05/2024 07:33:36}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:33:36}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:33:36}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:33:36}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:33:36}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:33:36}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:33:36}  {INFO}
{call}  {call invitation service(373218972)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:39:31}  {INFO}
{call}  {call invitation service(373218972)}  {register background message handler}  {06/05/2024 07:39:31}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:39:31}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:39:31}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:39:31}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:39:31}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:39:31}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:39:31}  {INFO}
{call}  {call invitation service(337690626)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:42:00}  {INFO}
{call}  {call invitation service(337690626)}  {register background message handler}  {06/05/2024 07:42:00}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:42:00}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:42:00}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:42:00}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:42:00}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:42:00}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:42:00}  {INFO}
{call}  {controller.invitation}  {send call invitation}  {06/05/2024 07:53:35}  {INFO}
{call}  {controller.invitation}  {send call invitation}  {06/05/2024 07:53:36}  {INFO}
{call}  {call invitation service(784450052)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:55:58}  {INFO}
{call}  {call invitation service(784450052)}  {register background message handler}  {06/05/2024 07:55:58}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:55:58}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:55:58}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:55:58}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:55:58}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:55:58}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:55:58}  {INFO}
{call}  {call invitation service(344440911)}  {using system calling ui, plugins size: 1}  {06/05/2024 07:58:45}  {INFO}
{call}  {call invitation service(344440911)}  {register background message handler}  {06/05/2024 07:58:45}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 07:58:45}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 07:58:45}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 07:58:45}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:58:45}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 07:58:45}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 07:58:45}  {INFO}
{call}  {call invitation service(44248487)}  {using system calling ui, plugins size: 1}  {06/05/2024 08:02:10}  {INFO}
{call}  {call invitation service(44248487)}  {register background message handler}  {06/05/2024 08:02:10}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 08:02:10}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 08:02:10}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 08:02:10}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:02:10}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:02:10}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 08:02:10}  {INFO}
{call}  {call invitation service(407709620)}  {using system calling ui, plugins size: 1}  {06/05/2024 08:03:07}  {INFO}
{call}  {call invitation service(407709620)}  {register background message handler}  {06/05/2024 08:03:07}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 08:03:07}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 08:03:07}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 08:03:07}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:03:07}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:03:07}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 08:03:07}  {INFO}
{call}  {call invitation service(1026281182)}  {using system calling ui, plugins size: 1}  {06/05/2024 08:03:57}  {INFO}
{call}  {call invitation service(1026281182)}  {register background message handler}  {06/05/2024 08:03:57}  {INFO}
{uikit}  {signaling core data}  {init data.}  {06/05/2024 08:03:57}  {INFO}
{uikit}  {signaling invitation data}  {init}  {06/05/2024 08:03:57}  {INFO}
{uikit}  {signaling advance invitation data}  {init}  {06/05/2024 08:03:57}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:03:57}  {INFO}
{log}  {init}  {==========================================Logs Configuration added.}  {06/05/2024 08:03:57}  {INFO}
{adapter}  {system service}  {init system service}  {06/05/2024 08:03:57}  {INFO}

It seems I found what the problem is. Indeed, in my service ZegoUIKitPrebuiltCallInvitationService().init simply did not execute because there was an error overriding the final field.

_videoCallDurationModel = VideoCallDurationModel(const Duration(seconds: 0));

Therefore, the error does not actually affect the package.

After I corrected it to

 _videoCallDurationModel.update(const Duration(seconds: 0));

The user's call began to be displayed.

Thank you for your help!

Have a nice day!