ConnectyCube / android-messenger-app

Chat and voice / video calling app using ConnectyCube
https://connectycube.com
Apache License 2.0
52 stars 23 forks source link

Android-iOS VOIP notifications not working as expected #71

Closed joeyoggie closed 3 years ago

joeyoggie commented 3 years ago

Hi,

We are building an appointments based app between patients and doctors. We are currently having issues sending notifications between Android and iOS.

We use a custom payload with notifications to detect the type of the appointment (voice call or video call)

The following scenarios work: Android > Android normal notification works fine iOS > iOS normal notification works fine Android > iOS normal notification works fine iOS > Android normal notification works fine

However, Android > iOS VOIP doesn't work. Nothing is received on the iOS device, even though the notification appears on the ConnectyCube Admin Panel notifications' queue.

Here's the method that sends the notification from Android to iOS: `

private void sendiOSVoipNotification(){
    Log.d(TAG, "sendiOSVoipNotification to " + partnerEmail + " - userId: " + partnerUserId);
    StringifyArrayList<Integer> userIds = new StringifyArrayList<>();
    userIds.add(partnerUserId);

    ConnectycubeEvent event = new ConnectycubeEvent();
    event.setUserIds(userIds);
    event.setEnvironment(ConnectycubeEnvironment.PRODUCTION);
    event.setNotificationType(ConnectycubeNotificationType.PUSH);
    event.setPushType(ConnectycubePushType.APNS_VOIP);

    JSONObject json = new JSONObject();
    try {
        json.put("notificationType", Constants.NOTIFICATION_TYPE_CALL);
        json.put("appointmentID", appointmentId);
        json.put("patientName", patientName);
        json.put("patientEmail", patientEmail);
        json.put("consultantName", doctorName);
        json.put("consultantEmail", doctorEmail);
        json.put("consultantImageURL", doctorImageUrl);
        json.put("date", dateString);
        json.put("timeTitle", timeString);
        json.put("communicationID", appointmentType);
        json.put("message", "Incoming Call. Tap to answer or reject");

        json.put("opponentId", personalUserId);
        json.put("recieverEmail", partnerEmail);

        json.put("calluuid", UUID.randomUUID().toString());
    } catch (Exception e) {
        e.printStackTrace();
    }

    //event.setMessage("");
    event.setMessage(json.toString());

    Log.d(TAG, "Data: " + json.toString());

    ConnectycubePushNotifications.createEvent(event).performAsync(new EntityCallback<ConnectycubeEvent>() {
        @Override
        public void onSuccess(ConnectycubeEvent event, Bundle args) {
            Log.d(TAG, "sendiOSVoipNotification createEvent onSuccess");
        }

        @Override
        public void onError(ResponseException errors) {
            Log.d(TAG, "sendiOSVoipNotification createEvent onError: " + errors.getMessage());
        }
    });
}`

For reference, here's the iOS method:

    let event = Event()
    //event.notificationType = .push
    var opponentID :UInt?
    if let opponentTemp = self.view?.opponentUser {
        opponentID = opponentTemp.id
    }
    else if CallVOIPHelper.instance.opponentId != nil {
        opponentID = CallVOIPHelper.instance.opponentId?.uintValue
    }
    else {return}
    //guard let userId = self.view?.user?.id else {return}
    event.usersIDs = [opponentID!] as [NSNumber]
    event.type = .oneShot
    event.pushType = .APNSVOIP
    var pushParameters = [String : String]()
    pushParameters["message"] = "\(AppData.shared.isDoctorProfile ? AppData.shared.userData?.profile?.fullName ?? "" : AppData.shared.userData?.fullName ?? "")"
    //pushParameters["ios_badge"] = "2"
    //pushParameters["ios_sound"] = "app_sound.wav"
    // custom params
    if let session = self.session {
        pushParameters["patientName"] = session.patientName
        pushParameters["consultantName"] = session.consultantName
        pushParameters["date"] = session.date
        pushParameters["timeTitle"] = session.timeTitle
        pushParameters["communicationID"] = String(session.communicationID ?? 0)
        pushParameters["consultantImageURL"] = session.consultantImageURL
        pushParameters["consultantEmail"] = session.consultantEmail
        pushParameters["patientEmail"] = session.patientEmail
        pushParameters["appointmentID"] = String(session.appointmentID ?? 0)
        pushParameters["notificationType"] = NotificationType.call.rawValue
        pushParameters["calluuid"] = UUID().uuidString
        pushParameters["recieverEmail"] = AppData.shared.isDoctorProfile ? session.patientEmail ?? "" : session.consultantEmail ?? ""
        pushParameters["opponentId"] = "\(self.view?.user.id ?? 0)"
    }
    print("DEBUG INFO: call notification push parameters : \r\n\(pushParameters.debugDescription)")
    if let jsonData = try? JSONSerialization.data(withJSONObject: pushParameters,
                                                  options: .prettyPrinted) {
        let jsonString = String(bytes: jsonData,
                                encoding: String.Encoding.utf8)
        event.message = jsonString
        Request.createEvent(event, successBlock: {(events) in
            print("success")
        }, errorBlock: {(error) in
            print("error , \(error.localizedDescription)")
        })
    }
TatankaConCube commented 3 years ago

For sending APNS_VOIP notification from Android just add the next parameter

json.put("ios_voip", 1);

to your JSON. About specific parameter for push notifications you can read there https://developers.connectycube.com/server/push_notifications?id=universal-push-notifications

joeyoggie commented 3 years ago

@TatankaConCube I tried adding that key to my json, but still the same. The notification appears on the Admin Panel, but the iOS device doesn't start the incoming call UI. The iOS can receive normal notifications though, it's only VOIP ones that are missing.

image

Here's a video of it in action: https://drive.google.com/file/d/1WCb4ItX4lJFRuGmmK6xNVSK9fBcBmdf5/view?usp=sharing

TatankaConCube commented 3 years ago

Can you please provide more status info about this notification? For it click on the 'sent' link on your screenshot and download JSON with the full report.

TatankaConCube commented 3 years ago

Additionally provide to us logs from the logcat with event creation

joeyoggie commented 3 years ago

@TatankaConCube here are the complete logs:

ConnectyCube Admin Panel notification json file: 3438214_log.json.gz

Chat initialization log: connecting_to_chat_log.txt

Sending notifications log: sending_notifications_log.txt

TatankaConCube commented 3 years ago

I will study your data tomorrow. For today try to delete this parameter event.setPushType(ConnectycubePushType.APNS_VOIP); and add json.put("ios_voip", 1); as I wrote before. In this case, SDK will send a universal push notification, and type will be used from your json.

TatankaConCube commented 3 years ago

@joeyoggie did you try my latest suggestion?

joeyoggie commented 3 years ago

@TatankaConCube Yes, I tried it when you first suggested it, but it was the same result. Notification sent and shows on the Admin Panel, but it's nothing on the recepient iOS device.

TatankaConCube commented 3 years ago

Did you delete pushType parameter from the event?

joeyoggie commented 3 years ago

Yes, indeed. I removed it and added 'ios_voip' to the json payload.

TatankaConCube commented 3 years ago

Hmm, it should work. Can you please provide the same log from the admin panel for the event, sent from iOS?

joeyoggie commented 3 years ago

@TatankaConCube sorry we had some issues in our BE server.

Here are the logs: Android > iOS: (nothing received on iOS device) image 3672087_log.json (android to ios).gz

iOS > Android: (works fine) 3672127_log.json (ios to android).gz

Edit: By nothing is received on iOS, I mean no VOIP calling received, I still however receive a normal notification message with 'Incoming Call. Tap to answer or reject' text I send in the 'message' field in the json payload.

TatankaConCube commented 3 years ago

I mean logs about worked push notification from iOS to iOS. Can you provide it?

DaveLomber commented 3 years ago

hi @joeyoggie

just to confirm couple of things:

Do you subscribe for VoIP push notifications? I mean , for iOS, you need to have 2 separate push subscriptions: one for normal pushes and another one for VoIP pushes.

Please confirm you do 2 push subscriptions on iOS

Here is more info regarding ios_voip parameter:

ios_voip=1 - will initiate VoIP push notification for iOS if user has VoIP push subscription. Otherwise - iOS user will receive standard iOS push. For Android - it will be a standard push.

So if a user has only normal pushes subscription then it will be a normal push initiated, despite you provide ios_voip=1.

joeyoggie commented 3 years ago

@TatankaConCube the above notification is the same one sent from iOS to iOS. I'll try and get you another log for iOS-iOS notification payload soon

@DaveLomber Yes, iOS is subscribed to VoIP. image

joeyoggie commented 3 years ago

@TatankaConCube here's the iOS-iOS notification: 3713856_log (ios to ios).json.gz

image

WhatsApp Image 2020-11-03 at 11 19 28 AM

DaveLomber commented 3 years ago

@joeyoggie so

same request with same payload

iOS->iOS works, but Android->iOS is not?

joeyoggie commented 3 years ago

@DaveLomber yeah exactly. iOS doesn't open the incoming call screen at all when calling from Android.

DaveLomber commented 3 years ago

@joeyoggie please show a code snippet how you create an event from iOS we need to compare with Android code above

joeyoggie commented 3 years ago

@DaveLomber here you go:

let event = Event()
    //event.notificationType = .push
    var opponentID :UInt?
    if let opponentTemp = self.view?.opponentUser {
        opponentID = opponentTemp.id
    }
    else if CallVOIPHelper.instance.opponentId != nil {
        opponentID = CallVOIPHelper.instance.opponentId?.uintValue
    }
    else {return}
    //guard let userId = self.view?.user?.id else {return}
    event.usersIDs = [opponentID!] as [NSNumber]
    event.type = .oneShot
    event.pushType = .APNSVOIP
    var pushParameters = [String : String]()
    pushParameters["message"] = "\(AppData.shared.isDoctorProfile ? AppData.shared.userData?.profile?.fullName ?? "" : AppData.shared.userData?.fullName ?? "")"
    //pushParameters["ios_badge"] = "2"
    //pushParameters["ios_sound"] = "app_sound.wav"

    // custom params
    if let session = self.session {
        pushParameters["patientName"] = session.patientName
        pushParameters["consultantName"] = session.consultantName
        pushParameters["date"] = session.date
        pushParameters["timeTitle"] = session.timeTitle
        pushParameters["communicationID"] = String(session.communicationID ?? 0)
        pushParameters["consultantImageURL"] = session.consultantImageURL
        pushParameters["consultantEmail"] = session.consultantEmail
        pushParameters["patientEmail"] = session.patientEmail
        pushParameters["appointmentID"] = String(session.appointmentID ?? 0)
        pushParameters["notificationType"] = NotificationType.call.rawValue
        pushParameters["calluuid"] = UUID().uuidString
        pushParameters["recieverEmail"] = AppData.shared.isDoctorProfile ? session.patientEmail ?? "" : session.consultantEmail ?? ""
        pushParameters["opponentId"] = "\(self.view?.user.id ?? 0)"
    }

    print("DEBUG INFO: call notification push parameters : \r\n\(pushParameters.debugDescription)")
    if let jsonData = try? JSONSerialization.data(withJSONObject: pushParameters,
                                                  options: .prettyPrinted) {
        let jsonString = String(bytes: jsonData,
                                encoding: String.Encoding.utf8)

        event.message = jsonString

        Request.createEvent(event, successBlock: {(events) in
            print("success")
        }, errorBlock: {(error) in
            print("error , \(error.localizedDescription)")
        })
    }
DaveLomber commented 3 years ago

You do not need this event.pushType = .APNSVOIP Just remove it as suggested above for Android

Then, also pass ios_voip=1

so it should be the SAME payload for both iOS/Android sides, please align

joeyoggie commented 3 years ago

@DaveLomber ok will remove it, but it works with it anyway.

TatankaConCube commented 3 years ago

in this case, you will have the same data from iOS and from Android in your callback

joeyoggie commented 3 years ago

@DaveLomber there's another issue, as you can see from the above screenshot, the iOS received the VoIP notification, but when we answer the call, nothing happens. It says 'BeSure audio connecting..." and that's it. It was working fine 10 days ago, and we haven't changed anything in the build as it's the same one on the App Store.

TatankaConCube commented 3 years ago

No activity for a long time. Closing... If you still have the same error, please create a new ticket with details.