Отправка push-уведомления на точки доступа Apple кажется успешной, но устройство не получает push-уведомление.C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Отправка push-уведомления на точки доступа Apple кажется успешной, но устройство не получает push-уведомление.

Сообщение Anonymous »

Я разработал приложение на .NET MAUI, которое поддерживает push-уведомления. Если я отправлю push-уведомление с веб-сайта Apple непосредственно на свое физическое устройство, оно будет получено и обработано должным образом.
Я также работал над нашим API push-уведомлений, который отправляет уведомления в Google Firebase. и APN Apple в зависимости от типа устройства, которое использует пользователь. Мне пришлось переписать код push-уведомлений Apple, поскольку наш код использовал конечную точку, которую предполагалось отключить в 2021 году, но каким-то образом ей удалось продолжать работать в рабочей среде.
Я написал класс ниже для отправки push-уведомлений в точки доступа Apple. Разработка не финальная, так как остались задачи типа хранения токена и запроса его каждые 20-60 минут. Мое решение во многом основано на различных ответах в более старой теме переполнения стека. Я перенес его в .NET 8.0, почистил и применил наши рекомендации по кодированию.

Код: Выделить всё

namespace MyNamespace
{
public class NewApplePushNotificationService : IPushNotificationService
{
private readonly string _url;
private readonly int _port;
private readonly string _certificatePath;
private readonly string _keyId;
private readonly string _bundleId;
private readonly string _teamId;

public NewApplePushNotificationService(bool isProduction, string certificatePath, string keyId, string bundleId, string teamId)
{
_url = isProduction ? "api.push.apple.com" : "api.sandbox.push.apple.com";
_port = 443; // 2197 is also a valid port according to Apple
_certificatePath = certificatePath;
_keyId = keyId;
_bundleId = bundleId;
_teamId = teamId;
}

public async Task Send(string title, string? subtitle, string message, string deviceToken)
{
var notification = new ApplePushNotification()
{
Aps = new ApplePushService()
{
Alert = new Alert(title, subtitle ?? string.Empty, message)
}
};

try
{
var json = JsonConvert.SerializeObject(notification);

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Debug.WriteLine($"{this}.Send > {nameof(json)} = {json}");
Debug.WriteLine($"{this}.Send > {nameof(ServicePointManager.SecurityProtocol)} = {ServicePointManager.SecurityProtocol}");

// Get absolute path of the private certificate.
var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (!Directory.Exists(directory))
{
Debug.WriteLine($"{this}.Send > Directory \"{directory}\" does not exist!");
return;
}

var certificatePath = $"{directory}\\{_certificatePath}";
if (!File.Exists(certificatePath))
{
Debug.WriteLine($"{this}.Send > File \"{certificatePath}\" does not exist!");
return;
}

// Get the private key.
ECDsa privateKey;

using (var reader = File.OpenText(certificatePath))
{
var ecPrivateKeyParameters = (ECPrivateKeyParameters)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();

var q = ecPrivateKeyParameters.Parameters.G.Multiply(ecPrivateKeyParameters.D).Normalize();
var qx = q.AffineXCoord.GetEncoded();
var qy = q.AffineYCoord.GetEncoded();
var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned();

var msEcp = new ECParameters { Curve = ECCurve.NamedCurves.nistP256, Q = { X = qx, Y = qy }, D = d };

privateKey = ECDsa.Create(msEcp);
}

// Create the authorization token.
var securityKey = new ECDsaSecurityKey(privateKey)
{
KeyId = _keyId
};

var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.EcdsaSha256);

var descriptor = new SecurityTokenDescriptor
{
IssuedAt = DateTime.Now,
// NotBefore = DateTime.UtcNow.AddSeconds(-5),
Issuer = _teamId,
SigningCredentials = credentials
};

var handler = new JwtSecurityTokenHandler();
var encodedToken = handler.CreateEncodedJwt(descriptor);

if (string.IsNullOrEmpty(encodedToken))
{
Debug.WriteLine($"{this}.Send > The creation of the authorization token \"{encodedToken}\" failed!");
return;
}

Debug.WriteLine($"{this}.Send >  {nameof(encodedToken)} = {encodedToken}");

// Send notification to Apple.
var httpClient = new HttpClient
{
DefaultRequestVersion = HttpVersion.Version20,
DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower
};

var apnsId = Guid.NewGuid().ToString("D");
Debug.WriteLine($"{this}.Send > {nameof(apnsId)} = {apnsId}");

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", encodedToken);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-topic", _bundleId);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-push-type", "alert");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-expiration", Convert.ToString(0));
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-priority", Convert.ToString(10));
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-id", apnsId);
// httpClient.DefaultRequestHeaders.TryAddWithoutValidation("apns-collapse-id", "test");

var url = $"https://{_url}:{_port}/3/device/{deviceToken}";

Debug.WriteLine($"{this}.Send > {nameof(url)} = {url}");

var response = await httpClient.PostAsync(new Uri(url), new StringContent(json, Encoding.UTF8, "application/json"));
if (response == null)
{
Debug.WriteLine($"{this}.Send > Invalid response object.");
return;
}

Debug.WriteLine($"{this}.Send > {nameof(response)} = {response} (Code {response.StatusCode})");
Debug.WriteLine($"{this}.Send > {nameof(response.IsSuccessStatusCode)} = {response.IsSuccessStatusCode}");

if (response.IsSuccessStatusCode)
{
try
{
var responseContent = await response.Content.ReadAsStringAsync();

Debug.WriteLine($"{this}.Send > {nameof(responseContent)} = {responseContent}");
}
catch (Exception exception)
{
Debug.WriteLine($"{this}.Send > Reading content failed. {nameof(exception)} = {exception}");
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception);
}
}
}
}
У меня «проблема» заключается в том, что выполнение кода работает в том смысле, что Apple сообщает мне, что все в порядке. В ответ я получаю код статуса 200. Никаких исключений не возникает, и объект ответа даже отражает идентификатор ASPN, который я отправляю в заголовке.
Но я не получаю push-уведомления на свой телефон. Опять же, если я отправлю его с веб-сайта, он сработает. Использование одной и той же информации (например, токена устройства, полезной нагрузки и т. д.).

Код: Выделить всё

MyNamespace.NewApplePushNotificationService.Send > json = {"Aps":{"Alert":{"Title":"My title","Subtitle":"My subtitle","Body":"My body"}}}
MyNamespace.NewApplePushNotificationService.Send > SecurityProtocol = Tls12
MyNamespace.NewApplePushNotificationService.Send > encodedToken = REDACTED
MyNamespace.NewApplePushNotificationService.Send > apnsId = 4fbf3ef3-6120-4f34-a3ea-0cd648e2cc69
MyNamespace.NewApplePushNotificationService.Send > url = https://api.sandbox.push.apple.com:443/3/device/REDACTED
MyNamespace.NewApplePushNotificationService.Send > response = StatusCode: 200, ReasonPhrase: 'OK', Version: 2.0, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
apns-id: 4fbf3ef3-6120-4f34-a3ea-0cd648e2cc69
apns-unique-id: 92f6386c-e17a-1add-a09e-aeae5d047ade
} (Code OK)
MyNamespace.NewApplePushNotificationService.Send > IsSuccessStatusCode = True
MyNamespace.NewApplePushNotificationService.Send > responseContent =
В случае, если кто-то задается вопросом: причина, по которой я явно установил TLS на значение 1.2, заключается в том, что я хотел быть абсолютно уверен во время своих тестов, что не такая глупая причина, как старый TLS по умолчанию, препятствует успеху. звонка.
Если кто-то заметит ошибку или догадается, что я мог сделать не так, дайте мне знать. Тот факт, что я могу получать и обрабатывать push-уведомления на своем телефоне, когда они отправляются с веб-сайта Apple, означает, что телефон хорошо их обрабатывает (разрешения, события и т. д.). Тот факт, что Apple подтверждает мой вызов push-уведомления из API с помощью 200, означает, что Apple говорит, что все в порядке. Но что-то явно не так, и я в замешательстве.

Подробнее здесь: https://stackoverflow.com/questions/790 ... h-notifica
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»