使用 Azure 通知中心的 iOS 推送通知

问题描述

我绝对没有运气在 Xamarin Forms 项目中获得在 iOS 中工作的推送通知

在 AppDelegate.cs 中,我在 FinishedLaunching 覆盖中调用以下内容

MSNotificationHub.Start("Endpoint=sb://[redacted].servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=[redacted]","[redacted]");

用户在应用生命周期中进一步登录后,我还使用他们的用户标签注册用户,如下所示:

    public async Task UpdateTags(string token)
    {
        await Task.Run(() =>
        {
            try
            {
                // No point registering tags until the user has signed in and we have a device token
                if (CurrentAccount == null)
                {
                    Console.WriteLine($"UpdateTags cancelled: Account is null");
                    return;
                }
                var tag = $"user:{CurrentAccount.UserName}";
                Console.WriteLine($"Registering tag: {tag}");
                MSNotificationHub.AddTag(tag);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error registering tag: {e.ToString()}");
            }
        });
    }

我已经在通知中心正确配置了 Apple (APNS) 设置,使用了令牌认证模式(多次验证了四个字段)。证书(签名身份)是“iOS 分发”,标识符包与我在配置中的完全匹配(不使用通配符),密钥启用了 Apple 推送通知服务 (APNs),并且配置文件具有平台:iOS 和类型:应用商店。

我将应用程序推送到 TestFlight,因为我无法访问物理 Mac(我们使用 Cloud mac 进行开发)。当我从安装了该应用的个人 iPhone 查看设备日志时,我在运行它时看到以下内容

<Notice>: Registered for push notifications with token: [redacted]
<Notice>: Registering tag: user:[redacted]

日志中根本没有“Error registering tag”或“UpdateTags cancelled”的实例,这告诉我方法调用成功无一例外。但是,当我尝试向空白/空标签或测试用户的特定标签发送测试通知时,没有收到任何通知,消息仅显示“消息已成功发送,但没有匹配的目标”。

此外,当我使用 var registrations = await hub.GetAllRegistrationsAsync(0); 提取所有注册时,我只能看到我在 Android 方面的成功测试中的 FCM (Firebase/Android) 注册

我完全不知所措,碰壁了,因为没有抛出异常,而且似乎无法解决幕后发生的事情。

这也是我的第二次尝试 - 我使用了更复杂的 SBNotificationHub 实现并获得了相同的结果 - 没有例外,一切看起来都很好。

解决方法

您可以尝试实现 MSInstallationLifecycleDelegate 接口,这将允许您检查安装是否成功或失败保存在后端。

// Set a listener for lifecycle management
MSNotificationHub.SetLifecycleDelegate(new InstallationLifecycleDelegate());

// Implementation of the lifecycle listener.
public class InstallationLifecycleDelegate : MSInstallationLifecycleDelegate
{
    public InstallationLifecycleDelegate()
    {
    }

    public override void DidFailToSaveInstallation(MSNotificationHub notificationHub,MSInstallation installation,NSError error)
    {
        Console.WriteLine($"Save installation failed with exception: {error.LocalizedDescription}");
    }

    public override void DidSaveInstallation(MSNotificationHub notificationHub,MSInstallation installation)
    {
        Console.WriteLine($"Installation successfully saved with Installation ID: {installation.InstallationId}");
    }
}
,

感谢指向另一个问题的评论,我确定我需要做的就是确保我的标签注册在主 UI 线程上运行。我更新后的代码如下:

<!DOCTYPE html>
<html style="background-color:black; margin:0;padding:0;" lang="en-US">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<meta charset="utf-8"/>
<link rel="icon" href="icon.png"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<meta name="description" content="Description"/>
<title>MyTitle</title>
<style>
a{
    color: inherit;
    text-decoration: none;
}
*{
    margin:0;
    padding:0;
}
#heading{
    color: white;
    text-align: center;
    font-size: 24px;
    font-weight: 420 bold;
    font-family: sans-serif;
    text-shadow: 2px 2px red;
    margin-right: 10px;
    margin-top: 20px;
}
#description{
    color: green;
    text-align: center;
    font-size: 19px;
    font-weight: 69 bold;
    font-family: serif;
    text-shadow: 1px 1px white;
    margin-right: 10px;
    margin-top: 20px;
}
#cursor{
    text-align: initial;
    position: absolute;
    left: 0;
  font-weight: 35;
  font-size: 25px;
  color: #2E3D48;
  -webkit-animation: 1s blink step-end infinite;
  -moz-animation: 1s blink step-end infinite;
  -ms-animation: 1s blink step-end infinite;
  -o-animation: 1s blink step-end infinite;
  animation: 1s blink step-end infinite;
}
#field{
    color: white;
    text-align: center;
    font-size: 20px;
    
}
#fieldDiv{
    background-color: #968786;
    text-align: center;
    width: 100%;
    height: 28px;}

@keyframes "blink" {
  from,to {
    color: transparent;
  }
  50% {
    color: black;
  }
}

@-moz-keyframes blink {
  from,to {
    color: transparent;
  }
  50% {
    color: black;
  }
}

@-webkit-keyframes "blink" {
  from,to {
    color: transparent;
  }
  50% {
    color: black;
  }
}

@-ms-keyframes "blink" {
  from,to {
    color: transparent;
  }
  50% {
    color: black;
  }
}

@-o-keyframes "blink" {
  from,to {
    color: transparent;
  }
  50% {
    color: black;
  }
}
#cursorContainer{
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
     user-select: none;
}
#bton{
    width: 20px;
    height: 20px;
}
</style>
</head>
<body>
    <h1 id="heading">
        Heading
    </h1>
    <p id="description">Description</p>
    <div id="fieldDiv">
        <p id="field"></p><p id="cursorContainer" onclick="hideCursor()"><span id="cursor">|</span></p>
    </div>
    <br/>
    <button id="bton" onclick="change();">
        <!--Always add the script on the bottom of the BODY tag since it contains the script-->
        <script type="text/javascript">
            var marginNum = screen.width/2;
            const screenWidth = screen.width;
            function checkCtrlA(){
                var ctrlPressed = false;
                window.addEventListener("keydown",function(e){
                    if(e.keyCode == 17){
                        ctrlPressed = true;
                    }
                });
                if(ctrlPressed){
                    window.addEventListener("keydown",function(e){
                        if(e.keyCode == 65){
                            hideCursor();
                        }
                    })
                }
            }
            window.onload = function(){
                const cursor = document.getElementById("cursor");
                const widthNeeded = innerWidth/2;
                cursor.style.marginLeft = widthNeeded.toString() + "px";
                cursor.style.cursor = "default";

            };
            const divToHide = document.getElementById("fieldDiv");
            divToHide.onclick = hideCursor;
            function printf(val){
                console.log(val);
            }
            document.getElementById("fieldDiv").addEventListener('click',function(){
                const element = document.getElementById("cursor");
                element.style.visibility = "hidden";
            });
            document.getElementById("fieldDiv").addEventListener("mouseover",function(){
                const element = document.getElementById("cursor");
                element.style.visibility = "hidden";
            });
            document.getElementById("fieldDiv").addEventListener("mouseout",function(){
                const element = document.getElementById("cursor");
                element.style.visibility = "visible";
            });
            var currentText = document.getElementById("field").textContent;
            function change(){
                movePosCursor();
                currentText = document.getElementById("field").textContent += "a";
                document.getElementById("cursor").style.visibility = "visible";
            }
            function movePosCursor(){
                const element = document.getElementById("cursor");
                marginNum += 5;
                var widthInPx = marginNum.toString() + "px";
                element.style.marginLeft = widthInPx;

            }
            function hideCursor(){
                const element = document.getElementById("cursor");
                element.style.visibility = "hidden";
            }
            checkCtrlA();
        </script>
</body>
</html>