来自 Amazon SNS 的 VoIP 推送

VoIP Push from Amazon SNS

我正在尝试从 Amazon SNS 发送 VoIP 推送,有一个 firebase 函数可以在收到 VoIP_token 时创建 ARN 并使 SNS 推送 VoIP 推送。现在我面临一个问题。

=> 推送来自 didReceiveIncomingPushWith 负载,但是在这个委托方法中,我正在尝试更新 firebase 值,正如您在代码中看到的那样,这也有效,android 在 5 分钟后发送推送来自已在 firebase 功能中配置的 SNS,但问题是有时推送有时不推送,在开发版本中它工作正常但是当我投入试飞时它经常工作

扩展 AppDelegate : PKPushRegistryDelegate {

@available(iOS 8.0, *)
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
    if #available(iOS 10.0, *) {
        Timer.scheduledTimer(withTimeInterval: 30, repeats: true) {_ in
            self.myMethod()
        }
    }
    else {
        Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.myMethod), userInfo: nil, repeats: true)
    }

    let token = credentials.token.map { String(format: "%02x", [=10=]) }.joined()

    voipTokenLogin = token
    voip_Token = token
    UserDefaults.standard.set(voipTokenLogin, forKey: "voip_Push_From_Amazon_SNS")
    var objRef : DatabaseReference!
    _ = String()

    if MyCurrentUSERID != "" && isUserLoggedIn {
        objRef = Database.database().reference().child("user").child(MyCurrentUSERID)
        let battery = UIDevice.current.batteryLevel * 100
        let Intbattery = Int(battery)
        let dict = [
            "isOnline" : true,
            "isGps" : true,
            "voip_token": voip_Token,
            "Battery" : Intbattery,
            "lastSeen" : Int(Date().millisecondsSince1970),
            "timeStamp" : Date().millisecondsSince1970
            ] as [String : Any]
        objRef.updateChildValues(dict)
    }
    else{
    }
}

@available(iOS 8.0, *)

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void){
    var arrTemp = [AnyHashable: Any]()
    arrTemp = payload.dictionaryPayload
    let _ : Dictionary <String, AnyObject> = arrTemp["aps"] as! Dictionary<String, AnyObject>
    if isUserHasLoggedInWithApp // Check this flag then only proceed
    {
        if UIApplication.shared.applicationState == UIApplicationState.background || UIApplication.shared.applicationState == UIApplicationState.inactive
        {
            if checkForIncomingCall
            {
                Locator.currentPosition(accuracy: .city, onSuccess: { (loc) -> (Void) in
                    isUpdatedUsingSilentPush = true

                    if self.isUserLoggedIn{
                        if !isUploadingRecentLocation {
                            if !self.sendOneUpdate{
                    self.sendLocationToFirebase(manager: Locator, Location: loc)
                            }
                        }
                    }

                }) { (err, loct) -> (Void) in
                    print(err)
                    print(loct as Any)
                }
                //
                var objRef : DatabaseReference!
                if MyCurrentUSERID != "" {
                    objRef = Database.database().reference().child("user").child(MyCurrentUSERID)
                    let dict = [
                        "timeStamp" : Date().millisecondsSince1970,
                        "isOnline" : true,
                        "isGps" : true,
                        "lastSeen" : Int(Date().millisecondsSince1970)
                        ] as [String : Any]

                    objRef.updateChildValues(dict)

                      var strTitle : String = dict["alertTitle"] as? String ?? "\(MyCurrentUSERID)"
                    let strBody : String = dict["alertBody"] as? String ?? "push arrived successfully"
                    strTitle = strTitle + "\n" + strBody
                    self.myMethod()
                    let notificationIncomingCall = UILocalNotification()
                    notificationIncomingCall.fireDate = Date(timeIntervalSinceNow: 1)
                   notificationIncomingCall.alertBody =  strTitle
                    notificationIncomingCall.alertAction = "Open"
                    notificationIncomingCall.soundName = "SoundFile.mp3"
                    notificationIncomingCall.category = dict["category"] as? String ?? ""
                    //"As per payload you receive"
                    notificationIncomingCall.userInfo = ["key1": "Value1"  ,"key2": "Value2" ]
                UIApplication.shared.scheduleLocalNotification(notificationIncomingCall)
                }

            }
            else
            {
                //  something else
            }

        }
    }
    completion()
}

您使用 Xcode 11 和 iOS13 吗? Apple 对 VoIP 推送通知进行了重大更改。使用 VoIP 时,您需要向 CallKit 报告 "incoming call"。

On iOS 13.0 and later, if you fail to report a call to CallKit, the system will terminate your app. Repeatedly failing to report calls may cause the system to stop delivering any more VoIP push notifications to your app. If you want to initiate a VoIP call without using CallKit, register for push notifications using the UserNotifications framework instead of PushKit.

https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry

我已经查看了您的代码,我认为您需要对 VOIP 进行一些说明。

当您收到 VOIP 推送时,您的应用最多激活 30 秒。

我注意到您在收到推入 iOS 设备时执行了一些繁重的操作。我认为这是您代码中的主要问题。

解决这个问题

降低 GPS 的精度级别。

删除或优化您的代码(只需将所需数据存储或更新到 firebase,避免无用的操作)

还有一件事,我想澄清一下推送有时来有时不来

  • 如果您尝试向同一台设备发送多个 Push,那么一些 跳过推送。
  1. 转到亚马逊 SNS
  2. 点击手机:推送通知
  3. 点击创建平台应用,
  4. 用户 Apple 凭据"Used for development in sandbox" 如果您想在沙盒上测试 voip 通知,请选中此复选框。
  5. 推送证书类型 -- Voip 推送证书
  6. 上传证书 .P12 文件。
  7. 保存表格并复制 ARN

https://docs.aws.amazon.com/sns/latest/dg/sns-send-custom-platform-specific-payloads-mobile-devices.html

创建 Lambda 函数。下面的代码示例适用于沙箱和生产环境。

// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'us-east-1'});

var amazonSNS = new AWS.SNS();

const isset = (s) => {
    return typeof s !== typeof undefined ? true : false;
};

exports.handler =  (event, context, callback) => {
    let data = event['body-json'];
    if (isset(data)) {
        let getAction = data['action'];
        let userToken = data['token'];
        let webPayload = data['payload'];

        if (isset(getAction) && getAction == 'APNS_VOIP') {
            amazonSNS.createPlatformEndpoint({
                PlatformApplicationArn: 'YOUR APPLICATION ARN',
                Token: userToken
            }, function (err, data1) {
                if (err) {
                    //handle error
                    console.log(err)
                } else {
                    //Publish notification
                    var endpointArn = data1.EndpointArn;
                    console.log("endpointArn",endpointArn);
                    var payload = {
                        default: 'Silent voip push notification',
                        APNS_VOIP: {
                            //aps:webPayload
                            "aps" : {
                                "alert" : {
                                    "title" : "Call Request"
                                },
                                "data":webPayload,
                                "content-available":1,
                                "category":"GENERAL"
                            }
                        }
                    };
                    payload.APNS_VOIP = JSON.stringify(payload.APNS_VOIP);
                    payload = JSON.stringify(payload);
                    amazonSNS.publish({
                        MessageStructure: 'json',
                        Message: payload,
                        MessageAttributes:{
                            "AWS.SNS.MOBILE.APNS.PRIORITY":{"DataType":"String","StringValue":"10"}, 
                            "AWS.SNS.MOBILE.APNS.PUSH_TYPE":{"DataType":"String","StringValue":"voip"} 
                        },
                        TargetArn: endpointArn
                    }, function (err, data2) {
                        if (err) {
                            //handle error
                            console.log(err)
                        } else {
                            var params = {
                                EndpointArn: endpointArn /* required */
                            };
                            //Deleting platform endpoint after sending a voipNotification; 
                            amazonSNS.deleteEndpoint(params, function (err, data3) {
                                if (err) {
                                    //handle error
                                    //console.log(err);
                                    callback(null, {
                                        "status": "error",
                                        "data": [],
                                        "message": []
                                    });
                                } else {
                                    //code success
                                    console.log("delete",data3);
                                    callback(null, {
                                        "status": "Success",
                                        "data": data3,
                                        "message":"notification sent successfully"
                                    });
                                }
                            });
                        }
                    });
                }
            });
        }
        else if (isset(getAction) && getAction == 'APNS_VOIP_SANDBOX') {
            amazonSNS.createPlatformEndpoint({
                PlatformApplicationArn: 'YOUR APPLICATION ARN',
                Token: userToken
            }, function (err, data1) {
                if (err) {
                    //handle error
                    console.log(err)
                } else {
                    //Publish notification
                    var endpointArn = data1.EndpointArn;
                    console.log("endpointArn",endpointArn);
                    var payload = {
                            default: 'Silent voip push notification',
                            APNS_VOIP_SANDBOX: {
                        "aps" : {
                            "alert" : {
                                "title" : "Call Request"
                            },
                            "data":webPayload,
                            "content-available":1,
                            "category":"GENERAL"
                        }
                    }
                        };
                    payload.APNS_VOIP_SANDBOX = JSON.stringify(payload.APNS_VOIP_SANDBOX);
                    payload = JSON.stringify(payload);
                    amazonSNS.publish({
                        MessageStructure: 'json',
                        Message: payload,
                        MessageAttributes:{
                            "AWS.SNS.MOBILE.APNS.PRIORITY":{"DataType":"String","StringValue":"10"}, 
                            "AWS.SNS.MOBILE.APNS.PUSH_TYPE":{"DataType":"String","StringValue":"voip"} 
                        },
                        TargetArn: endpointArn
                    }, function (err, data2) {
                        if (err) {
                            //handle error
                            console.log(err)
                        } else {
                            var params = {
                                EndpointArn: endpointArn /* required */
                            };
                            //Deleting platform endpoint after sending a voipNotification; Ref: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#deleteEndpoint-property
                            amazonSNS.deleteEndpoint(params, function (err, data3) {
                                if (err) {
                                    //handle error
                                    //console.log(err);
                                    callback(null, {
                                        "status": "error",
                                        "data": [],
                                        "message": []
                                    });
                                } else {
                                    //code success
                                    console.log("delete",data3);
                                    callback(null, {
                                        "status": "Success",
                                        "data": data3,
                                        "message":"notification sent successfully"
                                    });
                                }
                            });
                        }
                    });
                }
            });
        }
        else {
            callback(null, {
                "status": "error",
                "data": [],
                "message": "You have not posted valid data."
            });
        }
    }

};