ConnectyCube / connectycube-flutter-call-kit

A Flutter plugin for displaying call screen when the app in the background or terminated.
https://developers.connectycube.com/flutter
Apache License 2.0
57 stars 77 forks source link

App not Launching or going to Foreground from Background when click on accept action button ( ONLY ANDROID ) #113

Closed mrcse closed 10 months ago

mrcse commented 11 months ago

An issue I've encountered with the package. For a clearer understanding, I have attached the relevant code example.

After testing on multiple Android devices, I've observed that when our application is running in the background and a call notification is received, there's a glitch in its behavior. Upon clicking the "accept" button on the call notification, the code responsible for navigating to the call screen is executed. However, this does not bring the application to the foreground. Instead, the application remains in the background.

To ensure that the issue isn't with the callback function, I verified the 'onAcceptCallback'. It appears to be functioning correctly because when I manually bring the application to the foreground after clicking "accept", I can see that it has already navigated to the call screen.

*NOTE: This issue only on android side on ios it works fine

import 'dart:developer';

import 'package:bridge_health/core/models/incoming_call_model.dart';
import 'package:bridge_health/core/services/notification_services.dart';
import 'package:bridge_health/core/services/services.dart';
import 'package:bridge_health/core/utils/theme/theme.dart';
import 'package:bridge_health/firebase_options.dart';
import 'package:bridge_health/ui/screens/audio_video_chat/audio/audio_chat_screen.dart';
import 'package:bridge_health/ui/screens/audio_video_chat/video/video_chat_screen.dart';
import 'package:connectycube_flutter_call_kit/connectycube_flutter_call_kit.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

import 'core/services/navigator_services.dart';
import 'core/services/route_generator.dart';
import 'core/utils/log/custom_loger.dart';

@pragma('vm:entry-point')
Future<void> backgroundMessageHandler(RemoteMessage message) async {
  if (message.notification == null &&
      message.data['channelKey'] == "message_channel") {
    final data = message.data;

    if (data['isCalling'].toString().contains('true')) {
      final model = IncomingCallModel.fromMap(data);
      await handleIncomingCall(model);
    } else if (data['isCallHangup'].toString().contains('true')) {
      // await ConnectycubeFlutterCallKit.instance.;
    }
  }
}

@pragma('vm:entry-point')
Future<void> onCallAcceptedWhenTerminated(CallEvent event) async {
  final model = IncomingCallModel.fromMap(event.userInfo ?? {});
  if (FirebaseAuth.instance.currentUser != null) {
    if (model.isVideoCall.contains('true')) {
      NavigationService.navigateTo(VideoChatScreen.route, arguments: {
        'channelName': model.rtcChannel,
        'token': model.rtcToken,
        'uid': 10,
        'userName': model.callerName,
        'userProfile': model.callerPhotoUrl,
        'otherUserFcm': model.fcmToken,
      });
    } else {
      NavigationService.navigateTo(AudioChatScreen.route,
          arguments: AudioCallArguments(
              uid: 10,
              isVideo: false,
              channelName: model.rtcChannel,
              token: model.rtcToken,
              userProfile: model.callerPhotoUrl,
              otherUserFcm: model.fcmToken,
              userName: model.callerName));
    }
  }
}

@pragma('vm:entry-point')
Future<void> onCallRejectedWhenTerminated(CallEvent event) async {
  final model = IncomingCallModel.fromMap(event.userInfo ?? {});

  NotificationManager.instance.sendSilentNotification(
      data: {'isCallHangup': true}, token: model.fcmToken);
}

Future<void> _onCallAccepted(CallEvent callEvent) async {
  final model = IncomingCallModel.fromMap(callEvent.userInfo ?? {});
  log('Call Accepted Using Call Kit');
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  if (FirebaseAuth.instance.currentUser != null) {
    if (model.isVideoCall.contains('true')) {
      NavigationService.navigateTo(VideoChatScreen.route, arguments: {
        'channelName': model.rtcChannel,
        'token': model.rtcToken,
        'uid': 10,
        'userName': model.callerName,
        'userProfile': model.callerPhotoUrl,
        'otherUserFcm': model.fcmToken,
      });
    } else {
      NavigationService.navigateTo(AudioChatScreen.route,
          arguments: AudioCallArguments(
              uid: 10,
              isVideo: false,
              channelName: model.rtcChannel,
              token: model.rtcToken,
              userProfile: model.callerPhotoUrl,
              otherUserFcm: model.fcmToken,
              userName: model.callerName));
    }
  }
}

Future<void> _onCallRejected(CallEvent callEvent) async {
  final model = IncomingCallModel.fromMap(callEvent.userInfo ?? {});

  NotificationManager.instance.sendSilentNotification(
      data: {'isCallHangup': true}, token: model.fcmToken);
}

Future<void> main() async {
  final log = CustomLogger(className: 'main');
  try {
    await Services.initializeApp();
    ConnectycubeFlutterCallKit.instance.init(
      onCallAccepted: _onCallAccepted,
      onCallRejected: _onCallRejected,
    );
    ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: false);
    ConnectycubeFlutterCallKit.onCallRejectedWhenTerminated =
        onCallRejectedWhenTerminated;
    ConnectycubeFlutterCallKit.onCallAcceptedWhenTerminated =
        onCallAcceptedWhenTerminated;
    FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
    runApp(MyApp());
  } catch (e) {
    log.e("$e");
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        navigatorKey: NavigationService.navigatorKey,
        onGenerateRoute: RouteGenerator.generateRoute,
        theme: AppTheme.lightTheme,
        locale: const Locale("en"),
        title: "Bridge Health",
        initialRoute: '/');
  }
}

Future<void> handleIncomingCall(IncomingCallModel model) async {
  CallEvent callEvent = CallEvent(
      sessionId: model.id,
      callType: model.isVideoCall.contains('true') ? 1 : 0,
      callerId: 0,
      callerName: model.callerName,
      opponentsIds: {10},
      userInfo: model.toMap());
  ConnectycubeFlutterCallKit.showCallNotification(callEvent);
}
mrcse commented 11 months ago

flutter doctor -v

[✓] Flutter (Channel stable, 3.13.6, on macOS 14.0 23A344 darwin-x64, locale en-PK)
    • Flutter version 3.13.6 on channel stable at /usr/local/Caskroom/flutter/3.7.0/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ead455963c (9 days ago), 2023-09-26 18:28:17 -0700
    • Engine revision a794cf2681
    • Dart version 3.1.3
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /Users/mrcse/Library/Android/sdk
    • Platform android-33, build-tools 33.0.1
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] VS Code (version 1.82.3)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.74.0

[✓] Connected device (3 available)
    • Jamshid’s iPhone (mobile) • 00008120-001170143AC0C01E • ios            • iOS 17.0.2 21A351
    • macOS (desktop)           • macos                     • darwin-x64     • macOS 14.0 23A344 darwin-x64
    • Chrome (web)              • chrome                    • web-javascript • Google Chrome 113.0.5672.126

[✓] Network resources
    • All expected network resources are available.

• No issues found!
TatankaConCube commented 10 months ago

your case looks very similar to this https://github.com/ConnectyCube/connectycube-flutter-call-kit/issues/111, have you tried this solution https://github.com/ConnectyCube/connectycube-flutter-call-kit/issues/111#issuecomment-1727946091

mrcse commented 10 months ago

I added the SYSTEM_ALERT_WINDOW permission and added a popup for the user to accept the app overlay permission and this works Thanks