'.NET5 send push notification to Apple devices
At the moment I'm programming a REST service in .NET5 for Apple Wallet. All works fine now, registering, unregistering, manual update a card. The problem is the push notification, I know there are a lot of code stuff, how to implement a .NET Apple push notification service, but nothing works for me. I read, I have to use the Pass Type ID certificate and the push token, I get while registering a new wallet card on the Apple device. Here is my code for the push notification stuff
[HttpGet]
[Route("passes/{passTypeIdentifier}/{serialNumber}/sendpushnotification")]
public async Task<IActionResult> SendPushNotificationToAppleAsync(string passTypeIdentifier, string serialNumber)
{
var devices = await _context.GetApplePassDevicesAsync(serialNumber, passTypeIdentifier).ConfigureAwait(false);
if (!devices.Any()) {
return NotFound();
}
try {
foreach (var device in devices) {
await SendEmptyApplePushNotificationAsync(device.PushToken).ConfigureAwait(false);
await _context.SaveApplePushNotificationAsync(device.DeviceLibraryIdentifier, device.PushToken).ConfigureAwait(false);
}
return Ok();
} catch (Exception ex) {
_logger.LogError($"SendPushNotification error: [{ex.Message}]");
return NotFound();
}
}
private async Task SendEmptyApplePushNotificationAsync(string pushToken)
{
_logger.LogDebug("Trying to send push notification.");
const string server = "api.sandbox.push.apple.com"; // Develop
using var tcpClient = new TcpClient(server, 443);
await using var sslStream = new SslStream(
tcpClient.GetStream(),
false,
ValidateServerCertificate,
null);
try {
var certs = new X509Certificate2Collection();
X509Certificate cert = await GetAppleServerCertificateAsync().ConfigureAwait(false);
certs.Add(cert);
await sslStream.AuthenticateAsClientAsync(server, certs, SslProtocols.Tls12, true).ConfigureAwait(false);
} catch (AuthenticationException exp) {
throw new AuthenticationException(exp.Message);
} catch (IOException exp) {
throw new IOException(exp.Message);
}
var memoryStream = new MemoryStream();
var writer = new BinaryWriter(memoryStream);
writer.Write((byte) 0);
writer.Write((byte) 0);
writer.Write((byte) 32);
writer.Write(HexStringToByteArray(pushToken.ToUpper()));
var payload = new JObject { new JProperty("aps") };
var json = JsonConvert.SerializeObject(payload);
writer.Write((byte) 0);
writer.Write((byte) json.Length);
var b1 = Encoding.UTF8.GetBytes(json);
writer.Write(b1);
writer.Flush();
var array = memoryStream.ToArray();
await sslStream.WriteAsync(array.AsMemory()).ConfigureAwait(false);
await sslStream.FlushAsync().ConfigureAwait(false);
}
private static byte[] HexStringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
Has anyone a tip for me, what's wrong? I also test port 2197, does not work.
Thank you!
Solution 1:[1]
For me, it works with HttpClient POST to /3/device/{pushToken}
(since netcoreapp3 where HTTP/2 had been added).
Check https://github.com/justdmitry/PassKitHelper/blob/master/PassKitHelper/PassKitHelper.cs#L61-L101
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Dmitry |