简体   繁体   中英

Azure Notification Hub receiving unexplained 'APNS Channel Expired' errors

I am having issues with Azure Notification Hub. My iOS devices are initially being registered correctly and receiving pushes. However occasionally one or two devices just inexplicably stop receiving push notifications at all. Debugging this issue it appears that the problem is due to APNS expiring the channel the device was registered with:

在此处输入图片说明

The time elapsed between device registration and pushes stopping was no more than 10 minutes. I can 100% guarantee that this device was not manually unregistered via the notification hub. I was using the app as normal, and received some pushes and then it stopped receiving any.

For reference, the app is registered to Azure Notification Hub through a WebAPI back end. For reference, here is the code which registers the device for pushes whenever the user logs in or the app returns to the foreground. Please let me know if I am doing anything incorrectly in this logic:

private async Task<string> RegisterDevice(string token)
{
    string newRegistrationId = null;

    if (!string.IsNullOrWhiteSpace(token))
    {
        var registrations = await _notificationHub.GetRegistrationsByChannelAsync(token, 100);
        foreach (var registration in registrations)
        {
            if (newRegistrationId == null)
            {
                newRegistrationId = registration.RegistrationId;
            }
            else
            {
                await _notificationHub.DeleteRegistrationAsync(registration);
            }
        }
    }

    return newRegistrationId ?? await _notificationHub.CreateRegistrationIdAsync();
}

public async Task<string> CreateOrUpdateRegistration(string userId, string token, string platform, string registrationId = null)
{
    var userDetail = await _userDetailRepo.GetAsync(userId);
    if (userDetail == null)
        throw new ApiException(HttpStatusCode.BadRequest, "User details could not be found");

    if (string.IsNullOrWhiteSpace(registrationId))
        registrationId = await RegisterDevice(token);

    RegistrationDescription registration;
    switch (platform)
    {
        case Settings.Platforms.Android:
            var gcmTemplate = "[REDACTED]"
            registration = new GcmTemplateRegistrationDescription(token, gcmTemplate);
            break;
        case Settings.Platforms.Ios:
            var apnsTemplate = "[REDACTED]";
            registration = new AppleTemplateRegistrationDescription(token, apnsTemplate);
            break;
        default:
            throw new ApiException(HttpStatusCode.BadRequest, "Platform not recognised");
    }

    registration.RegistrationId = registrationId;
    SetDeviceRegistrationTags(registration, userId, userDetail.TwingleAcceptedNotificationEnabled, userDetail.TwingleDeclinedNotificationEnabled, userDetail.MessageReceivedNotificationEnabled, userDetail.ConnectionDeletedNotificationEnabled);

    var registrationStale = false;
    try
    {
        await _notificationHub.CreateOrUpdateRegistrationAsync(registration);
    }
    catch (MessagingException e)
    {
        var webEx = e.InnerException as WebException;
        if (webEx != null && webEx.Status == WebExceptionStatus.ProtocolError)
        {
            var response = (HttpWebResponse)webEx.Response;
            if (response.StatusCode == HttpStatusCode.Gone)
            {
                registrationStale = true;
            }
        }
    }

    // if the registration is stale and/or removed then it needs to be re-created with a new registrationId
    if (registrationStale)
        registrationId = await CreateOrUpdateRegistration(userId, token, platform);

    return registrationId;
}

Can anyone tell me what causes the device to expire with APNS when no changes are made to its (at first successful) registration?

Devices must periodically re-register themselves with APNS to ensure they have a valid token. If they don't then they won't receive a push (and you will see the device registration disappear in Notifications Hub once the failure callback triggers its removal). This is by design: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html

The issue was because by default AppleTemplateRegistrationDescriptions specify 0 as a timeout value. This means that as soon as APNS fails to deliver one message to the device it is immediately removed; the is no leeway. To fix this I specified the Expiry property of the class so that there is a delay allowed between the notification being sent and it being acknowledged by the device. This has meant that no devices have since been unduly un-registered by APNS.

AppleTemplateRegistrationDescription registration = new AppleTemplateRegistrationDescription(DeviceToken) 
{ 
    BodyTemplate = new CDataMember(ApnsBodyTemplate)
};
registration.Expiry = DateTime.UtcNow.AddHours(2);
await client.CreateRegistrationAsync(registration);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM