我在Apple的TestFlight中有一个应用程序,我正在测试推送通知,当我在该应用程序上登录时,该通知可以正常工作,但是24小时后,我停止接收所有推送通知。但是,当我退出应用程序并重新登录时,我再次开始接收通知。我认为有些未知代码会使推送通知注册在一段时间后过期,但我不确定。代码在
下面应用委托
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
private SBNotificationHub Hub { get; set; }
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
});
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
global::Xamarin.Forms.Forms.Init();
SegmentedControlRenderer.Init();
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
Hub = new SBNotificationHub(WBUtility.ListenConnectionString, WBUtility.NotificationHubName);
// FacebookAuthBullshit.DeviceToken = deviceToken
if (App.Current.Properties.ContainsKey("DeviceToken"))
{
App.Current.Properties["DeviceToken"] = deviceToken.Description;
}
else
{
App.Current.Properties.Add("DeviceToken", deviceToken.Description);
}
// App.Current.SavePropertiesAsync();
Hub.UnregisterAllAsync(deviceToken, (error) => {
if (error != null)
{
System.Diagnostics.Debug.WriteLine("Error calling Unregister: {0}", error.ToString());
return;
}
NSSet tags = null; // create tags if you want
Hub.RegisterNativeAsync(deviceToken, tags, (errorCallback) => {
if (errorCallback != null)
System.Diagnostics.Debug.WriteLine("RegisterNativeAsync error: " + errorCallback.ToString());
});
});
}
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
ProcessNotification(userInfo, false);
}
//private static void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs unobservedTaskExceptionEventArgs)
//{
// var newExc = new Exception("TaskSchedulerOnUnobservedTaskException", unobservedTaskExceptionEventArgs.Exception);
// Windows.UI.Xaml.Navigation.PushAsync(new FacebookAuthBullshit());
// // LogUnhandledException(newExc);
//}
//private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
//{
// var newExc = new Exception("CurrentDomainOnUnhandledException", unhandledExceptionEventArgs.ExceptionObject as Exception);
// /// LogUnhandledException(newExc);
//}
void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
{
// Check to see if the dictionary has the aps key. This is the notification payload you would have sent
if (null != options && options.ContainsKey(new NSString("aps")))
{
//Get the aps dictionary
NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;
string alert = string.Empty;
//Extract the alert text
// NOTE: If you're using the simple alert by just specifying
// " aps:{alert:"alert msg here"} ", this will work fine.
// But if you're using a complex alert with Localization keys, etc.,
// your "alert" object from the aps dictionary will be another NSDictionary.
// Basically the JSON gets dumped right into a NSDictionary,
// so keep that in mind.
if (aps.ContainsKey(new NSString("alert")))
alert = (aps[new NSString("alert")] as NSString).ToString();
//If this came from the ReceivedRemoteNotification while the app was running,
// we of course need to manually process things like the sound, badge, and alert.
if (!fromFinishedLaunching)
{
//Manually show an alert
if (!string.IsNullOrEmpty(alert))
{
UIAlertView avAlert = new UIAlertView("Notification", alert, null, "OK", null);
avAlert.Show();
}
}
}
}
}
在登录期间被调用的客户端代码,特别是RegisterAsync
方法。注销我的应用程序后,然后重新登录此代码,即可正常运行。
public class RegisterClient
{
private string POST_URL;
private class DeviceRegistration
{
public string Platform { get; set; }
public string Handle { get; set; }
public string[] Tags { get; set; }
}
public RegisterClient(string backendEndpoint)
{
POST_URL = backendEndpoint + "/api/register";
}
public async Task RegisterAsync(string handle, IEnumerable<string> tags)
{
var regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
var deviceRegistration = new DeviceRegistration
{
Platform = "apns",
Handle = handle,
Tags = tags.ToArray<string>()
};
var statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
if (statusCode == HttpStatusCode.Gone)
{
// regId is expired, deleting from local storage & recreating
//var settings = App.Current.Properties;
//settings.Remove("__NHRegistrationId");
regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
}
if (statusCode != HttpStatusCode.Accepted && statusCode != HttpStatusCode.OK)
{
// log or throw
throw new System.Net.WebException(statusCode.ToString());
}
}
private async Task<HttpStatusCode> UpdateRegistrationAsync(string regId, DeviceRegistration deviceRegistration)
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + App.Current.Properties["AccessToken"].ToString());
var putUri = POST_URL + "/" + regId;
deviceRegistration.Handle = deviceRegistration.Handle.Replace("<", "").Replace(">", "").Replace(" ", "");
string json = JsonConvert.SerializeObject(deviceRegistration);
var response = await httpClient.PutAsync(putUri, new StringContent(json, Encoding.UTF8, "application/json"));
return response.StatusCode;
}
}
private async Task<string> RetrieveRegistrationIdOrRequestNewOneAsync()
{
// var settings = App.Current.Properties;
//if (!settings.ContainsKey("__NHRegistrationId"))
//{
string id = "";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + App.Current.Properties["AccessToken"].ToString());
var response = await httpClient.PostAsync(POST_URL+"?handle="+App.Current.Properties["DeviceToken"].ToString().Replace("<", "").Replace(">", "").Replace(" ", ""),new StringContent(""));
if (response.IsSuccessStatusCode)
{
string regId = await response.Content.ReadAsStringAsync();
regId = regId.Substring(1, regId.Length - 2);
id = regId;
//settings.Add("__NHRegistrationId", regId);
}
else
{
throw new System.Net.WebException(response.StatusCode.ToString());
}
}
// }
//return (string)settings["__NHRegistrationId"];
return id;
}
}
服务器代码
private NotificationHubClient hub;
public RegisterController()
{
hub = Notifications.Instance.Hub;
}
public class DeviceRegistration
{
public string Platform { get; set; }
public string Handle { get; set; }
public string[] Tags { get; set; }
}
// POST api/register
// This creates a registration id
[Authorize]
public async Task<string> Post(string handle = null)
{
string newRegistrationId = null;
// make sure there are no existing registrations for this push handle (used for iOS and Android)
if (handle != null)
{
var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
foreach (RegistrationDescription registration in registrations)
{
if (newRegistrationId == null)
{
newRegistrationId = registration.RegistrationId;
}
else
{
await hub.DeleteRegistrationAsync(registration);
}
}
}
if (newRegistrationId == null)
newRegistrationId = await hub.CreateRegistrationIdAsync();
return newRegistrationId;
}
// PUT api/register/5
// This creates or updates a registration (with provided channelURI) at the specified id
[Authorize]
public async Task<HttpResponseMessage> Put(string id, DeviceRegistration deviceUpdate)
{
RegistrationDescription registration = null;
switch (deviceUpdate.Platform)
{
case "mpns":
registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
break;
case "wns":
registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
break;
case "apns":
registration = new AppleRegistrationDescription(deviceUpdate.Handle);
break;
case "gcm":
registration = new GcmRegistrationDescription(deviceUpdate.Handle);
break;
default:
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
registration.RegistrationId = id;
var context = RequestContext.Principal;
var username = context.Identity.Name;
// add check if user is allowed to add these tags
registration.Tags = new HashSet<string>
{
"username:" + username
};
try
{
await hub.CreateOrUpdateRegistrationAsync(registration);
}
catch (MessagingException e)
{
ReturnGoneIfHubResponseIsGone(e);
}catch (Exception e)
{
e = e;
}
var test = await hub.GetAllRegistrationsAsync(1000);
test = test;
return Request.CreateResponse(HttpStatusCode.OK);
}
// DELETE api/register/5
[Authorize]
public async Task<HttpResponseMessage> Delete(string id)
{
await hub.DeleteRegistrationAsync(id);
return Request.CreateResponse(HttpStatusCode.OK);
}
private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
{
var webex = e.InnerException as WebException;
if (webex.Status == WebExceptionStatus.ProtocolError)
{
var response = (HttpWebResponse)webex.Response;
if (response.StatusCode == HttpStatusCode.Gone)
throw new HttpRequestException(HttpStatusCode.Gone.ToString());
}
}
}
}