react-native-webrtc / react-native-callkeep

iOS CallKit framework and Android ConnectionService for React Native
ISC License
917 stars 441 forks source link

RNCallKeep is not working on app background and Inactive States #202

Open pavanMude opened 4 years ago

pavanMude commented 4 years ago

Bug report

Description

I have implemented RNCallKeep features in such a way that when a push notification arrives, then it tries to display an incoming UI through RNCallKeepDisplayIncomingUI(). When the app is in foreground as per the logic If I click on answer button, it is redirecting to a specific page; howsoever, the functionality that I am mentioning wasn't working as expected when the app goes to background or inactive state.

In background state, on click of answer button, the expected behaviour is that app should change its state to foreground, open the app automatically and redirect to the specific screen. The navigation logic is working fine but it is not opening the app and behave according to the logic.

Help will be appreciated.

Versions

- Callkeep: 3.0.12
- React Native: 0.59.9
- iOS: 10.15.2
- Android: android 9.0
- Phone model: Nokia 5.1 plus 
isnifer commented 4 years ago

Same here. Killed an app. Calling to this device — no reaction.

@pavanMude Figured out — need to configure, for example, Firebase background messaging (https://bit.ly/3ej3hoN — react-native-firebase v5 docs NOT THE LATEST, but just my case).

Then you need to register headless task.

AppRegistry.registerHeadlessTask(
  'RNFirebaseBackgroundMessage',
  () => CallMessagingManager.backgroundMessageHandler
)

Inside this backgroundMessageHandler it's important to call methods:

RNCallKeep.setup(YOUR_OPTIONS)
RNCallKeep.setAvailable(true)
// rest of your call answer logic

After this at some moment (onAnswer, for example) you need to use something like that — react-native-invoke-app to return your app from background.

JustinBeBoy commented 4 years ago

@isnifer in the backgroundMessageHandler i setup Callkeep and display incomming call and after i call RNCallKeep.setCurrentCallActive(callUUID); i can't recive event endcall when i pressButtom endcall in screen ui can you tell me why and how i can catch event endcall? test in android

manuquentin commented 4 years ago

Hi @JustinBeBoy, to receive an event when someone hangup via callkeep, you have to register a listener.

JustinBeBoy commented 4 years ago

@manuquentin I registered all the events, when I test your example, I still get the endcall event, but when I process the notification in the background firebase, I don't get the endcall event when I click the end call button i test in nexsus 5x android 8.1 react native : 0.62

danjenkins commented 4 years ago

@JustinBeBoy can you explain what youre trying to do a bit clearer please? We can't help you unless you give us more information to go on

JustinBeBoy commented 4 years ago

@danjenkins code in file index.js: `function HeadlessCheck({ isHeadless }) { if (isHeadless) { // App has been launched in the background by iOS, ignore return null; }

return <App />;

}

registerMessing()

AppRegistry.registerComponent(appName, () => HeadlessCheck);`

this is my registerMessing function:

export const registerMessing = () => { messaging().setBackgroundMessageHandler(async remoteMessage => { console.log('Message handled in the background!', remoteMessage); try { const messData = remoteMessage.data ?? {} const type = messData.type ?? "" const data = messData.data if (type == NotiType.call) { const objectNoti = JSON.parse(data) console.log('Parse Object', objectNoti) await handlerCall(objectNoti) } console.log('Message handled in the background!', remoteMessage); } catch (err) { console.log('backgoundMessageHandler-error: ', err) } }); }

handlerCall function:

`const handlerCall = (object) => { return new Promise(async (resolve, reject) => { if (object.callStatus == CallStatus.end) { resolve() }

    let client = new StringeeClientCustoms()
    let stringeeCa = new StringeeCallCustoms()

    let mediaConnected = false
    let answered = false
    const callDidChangeSignalingState = ({ callId, code, reason, sipCode, sipReason }) => {}
    const callDidChangeMediaState = ({ callId, code, description }) => {}
    const callDidReceiveLocalStream = ({ callId }) => {
        console.log("CallScreen-callDidReceiveLocalStream: callID=" + callId);
        // updateHasReceivedLocalStream(true)
    };

    const callDidReceiveRemoteStream = ({ callId }) => {
        console.log("CallScreen-callDidReceiveRemoteStream: callID=" + callId);
        // updateHasReceivedRemoteStream(true)
    };

    const didReceiveDtmfDigit = ({ callId, dtmf }) => {
        console.log("CallScreen-didReceiveDtmfDigit: callId=" + callId + " -- dtmf=" + dtmf);
    };

    const didReceiveCallInfo = ({ callId, data }) => {
        console.log("CallScreen-didReceiveCallInfo: callId=" + callId + " -- data=" + data);
    };

    const didHandleOnAnotherDevice = ({ callId, code, description }) => {
        console.log("CallScreen-didHandleOnAnotherDevice: callId=" + callId + " -- code=" + code + " -- des=" + description);
        if (code == 2 || code == 3 || code == 4) {
            // Answered || Busy || End
            console.log("CallScreen-endCallAndDismissView")
            // endCallAndDismissView();
        }
    };
    const callEventHandlers = {
        onChangeSignalingState: callDidChangeSignalingState,
        onChangeMediaState: callDidChangeMediaState,
        onReceiveLocalStream: callDidReceiveLocalStream,
        onReceiveRemoteStream: callDidReceiveRemoteStream,
        onReceiveDtmfDigit: didReceiveDtmfDigit,
        onReceiveCallInfo: didReceiveCallInfo,
        onHandleOnAnotherDevice: didHandleOnAnotherDevice
    };
    const clientDidConnect = ({ userId }) => {
        console.log("_clientDidConnect - " + userId);
    }

    const clientDidDisConnect = () => {
        console.log("_clientDidDisConnect");
    };

    const clientDidFailWithError = () => {
        console.log("_clientDidFailWithError");
    };

    const clientRequestAccessToken = () => {
        console.log("_clientRequestAccessToken");
        // Token để kết nối tới Stringee server đã hết bạn. Bạn cần lấy token mới và gọi connect lại ở đây
        // this.refs.client.connect("NEW_TOKEN");
    };

    // Call events
    const callIncomingCall = ({ callId, from, to, fromAlias, toAlias, callType, isVideoCall, customDataFromYourServer }) => {
        console.log("-----------_callIncomingCall---------------", callId)
        stringeeCa.init(callEventHandlers)

        stringeeCa.initAnswer(object.callId, (status, code, message) => {
            console.log("initAnswer=======>", message);
        });
    };

    const clientEventHandlers = {
        onConnect: clientDidConnect,
        onDisConnect: clientDidDisConnect,
        onFailWithError: clientDidFailWithError,
        onRequestAccessToken: clientRequestAccessToken,
        onIncomingCall: callIncomingCall
    };

    const answerCall = ({ callUUID }) => {

        stringeeCa.answer(object.callId, (status, code, message) => {
            console.log("xxxxxxx" + message);
            RNCallKeep.startCall(callUUID, "LockApp", "Test")
            //@ts-ignore
            RNCallKeep.setCurrentCallActive(callUUID);
        })
    }

    const didReceiveStartCallAction = ({ handle }) => {
        console.log("didReceiveStartCallAction")
    };

    const didPerformSetMutedCallAction = ({ muted, callUUID }) => {
        console.log("didPerformSetMutedCallAction")
    };

    const didToggleHoldCallAction = ({ hold, callUUID }) => {
        console.log("didToggleHoldCallAction")
    };

    const endCall = ({ callUUID }) => {
        console.log("END CALL:=========")
        stringeeCa.hangup(object.callId, (status, code, message) => {
            console.log("CallScreen-callDidChangeSignalingState-hangup: status=3, mess=" + message);
            resolve()
        });
    };

    RNCallKeep.addEventListener('answerCall', answerCall);
    RNCallKeep.addEventListener('didReceiveStartCallAction', didReceiveStartCallAction);
    RNCallKeep.addEventListener('didPerformSetMutedCallAction', didPerformSetMutedCallAction);
    RNCallKeep.addEventListener('didToggleHoldCallAction', didToggleHoldCallAction);
    RNCallKeep.addEventListener('endCall', endCall);

    client.init(clientEventHandlers)
    client.connect(userTest)
    let uuid4 = uuidv4()
    RNCallKeep.displayIncomingCall(uuid4, "LockApp", "Test")
})

}`

when i call this code: RNCallKeep.startCall(callUUID, "LockApp", "Test") //@ts-ignore RNCallKeep.setCurrentCallActive(callUUID); screen call system show, but when i press button endcall in screen i don't get event endcall in RNCallKeep.addEventListener('endCall', endCall); i test in nexsus 5x android 8.1 react native : 0.62

pavanMude commented 4 years ago

@JustinBeBoy It is because that you are passing different callUUID to end call(). Remember you must pass same UUID on RNCallKeep DisplayUI (), which also be given in end call() as well. This will surely work.

const endCall = ({ callUUID }) => {
        console.log("END CALL:=========")
        stringeeCa.hangup(object.callId, (status, code, message) => {
            console.log("CallScreen-callDidChangeSignalingState-hangup: status=3, mess=" + message);
            resolve()
        });
    };
jason-shen commented 3 years ago

Same here. Killed an app. Calling to this device — no reaction.

@pavanMude Figured out — need to configure, for example, Firebase background messaging (https://bit.ly/3ej3hoN — react-native-firebase v5 docs NOT THE LATEST, but just my case).

Then you need to register headless task.


AppRegistry.registerHeadlessTask(

  'RNFirebaseBackgroundMessage',

  () => CallMessagingManager.backgroundMessageHandler

)

Inside this backgroundMessageHandler it's important to call methods:


RNCallKeep.setup(YOUR_OPTIONS)

RNCallKeep.setAvailable(true)

// rest of your call answer logic

After this at some moment (onAnswer, for example) you need to use something like that — react-native-invoke-app to return your app from background.

Just a question, This apply to android only right?

nikolov9996 commented 2 years ago

RNCallKeep.setAvailable(true)

this part ended 2 days of suffering with RN a big TY!

Irfanwani commented 3 months ago

I am trying to handle the calling when the app is in kille state. I tested the features in the foreground state and the listeners are working perfectly fine, but when the app is killed, the UI is shown but nothing happens when buttons are pressed, no callbacks in listeners are invoked.