在開發自己的蘋果推送服務時候,要合理的控制ios設備的Token,而這個Token是由蘋果服務器Apns產生的,就是每次app問Apns要Token,由蘋果服務器產生的Token會記錄到Apns裡面,我們需要根據該Token進行制定設備的消息推送,所有Token需要我們自己去記錄和管理,每個設備對應唯一的Token,而app的用戶登錄會有自己約束的別名,與該tokne進行關系綁定,這樣按該別名進行推送,就可以找到對應的Token,進而推送到該iso設備上,對應失效的Token我們需要訪問蘋果的feedbackServer,拿取失效的Token,然後把本地記錄的失效token進行移除。
注意事項:
1.建議和feedback服務器建立長連接,連接過於頻繁有可能被當做攻擊(簡簡單單的做一些測試時沒有關系的);所有在實際開發完成後,我們基本上可以半天與feedback服務器建立一次socket連接,拿取失效的token,
2.獲取的token是在上次你給你的應用發推送失敗時加feedback服務的,裡面會返回失敗的具體時間.
3.返回的數據由三部分組成,請看下面的圖:
構中包含三個部分,第一部分是一個上次發推送失敗的時間戳,第二個部分是device_token的長度,第三部分就是失效的device_token
貼下PushSharp中連接feedback的代碼
1 /// <summary> 2 /// FeedbackService 3 /// </summary> 4 public class FeedbackService 5 { 6 public FeedbackService(ApnsConfiguration configuration) 7 { 8 Configuration = configuration; 9 } 10 11 public ApnsConfiguration Configuration { get; private set; } 12 13 public delegate void FeedbackReceivedDelegate(string deviceToken, DateTime timestamp); 14 public event FeedbackReceivedDelegate FeedbackReceived; 15 16 public void Check() 17 { 18 var encoding = Encoding.ASCII; 19 20 var certificate = Configuration.Certificate; 21 22 var certificates = new X509CertificateCollection(); 23 certificates.Add(certificate); 24 25 var client = new TcpClient(Configuration.FeedbackHost, Configuration.FeedbackPort); 26 27 var stream = new SslStream(client.GetStream(), true, 28 (sender, cert, chain, sslErrs) => { return true; }, 29 (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; }); 30 31 stream.AuthenticateAsClient(Configuration.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Tls, false); 32 33 34 //Set up 35 byte[] buffer = new byte[4096]; 36 int recd = 0; 37 var data = new List<byte>(); 38 39 //Get the first feedback 40 recd = stream.Read(buffer, 0, buffer.Length); 41 42 //Continue while we have results and are not disposing 43 while (recd > 0) 44 { 45 // Add the received data to a list buffer to work with (easier to manipulate) 46 for (int i = 0; i < recd; i++) 47 data.Add(buffer[i]); 48 49 //Process each complete notification "packet" available in the buffer 50 while (data.Count >= (4 + 2 + 32)) // Minimum size for a valid packet 51 { 52 var secondsBuffer = data.GetRange(0, 4).ToArray(); 53 var tokenLengthBuffer = data.GetRange(4, 2).ToArray(); 54 55 // Get our seconds since epoch 56 // Check endianness and reverse if needed 57 if (BitConverter.IsLittleEndian) 58 Array.Reverse(secondsBuffer); 59 var seconds = BitConverter.ToInt32(secondsBuffer, 0); 60 61 //Add seconds since 1970 to that date, in UTC 62 var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds); 63 64 //flag to allow feedback times in UTC or local, but default is local 65 if (!Configuration.FeedbackTimeIsUTC) 66 timestamp = timestamp.ToLocalTime(); 67 68 69 if (BitConverter.IsLittleEndian) 70 Array.Reverse(tokenLengthBuffer); 71 var tokenLength = BitConverter.ToInt16(tokenLengthBuffer, 0); 72 73 if (data.Count >= 4 + 2 + tokenLength) 74 { 75 76 var tokenBuffer = data.GetRange(6, tokenLength).ToArray(); 77 // Strings shouldn't care about endian-ness... this shouldn't be reversed 78 //if (BitConverter.IsLittleEndian) 79 // Array.Reverse (tokenBuffer); 80 var token = BitConverter.ToString(tokenBuffer).Replace("-", "").ToLower().Trim(); 81 82 // Remove what we parsed from the buffer 83 data.RemoveRange(0, 4 + 2 + tokenLength); 84 85 // Raise the event to the consumer 86 var evt = FeedbackReceived; 87 if (evt != null) 88 evt(token, timestamp); 89 } 90 else 91 { 92 continue; 93 } 94 95 } 96 97 //Read the next feedback 98 recd = stream.Read(buffer, 0, buffer.Length); 99 } 100 101 try 102 { 103 stream.Close(); 104 stream.Dispose(); 105 } 106 catch { } 107 108 try 109 { 110 client.Client.Shutdown(SocketShutdown.Both); 111 client.Client.Dispose(); 112 } 113 catch { } 114 115 try { client.Close(); } 116 catch { } 117 } 118 } View Code下面是處理邏輯:
1 /// <summary> 2 /// 處理失效的Token邏輯信息 3 /// </summary> 4 public class TokenProvider 5 { 6 private FeedbackService fs = null; 7 private int hour = 12; 8 private string CID; 9 10 public TokenProvider(ApnsConfiguration cf, string CID) 11 { 12 this.fs = fs = new FeedbackService(cf); 13 this.CID = CID; 14 try 15 { 16 int hour = int.Parse(ConfigurationManager.AppSettings["ManagerTokenHour"]);//Token的控制時間 17 } 18 catch { hour = 12; } 19 } 20 21 /// <summary> 22 /// 開啟處理失效的Token邏輯信息 23 /// </summary> 24 /// <param name="cf"></param> 25 public void Init() 26 { 27 try 28 { 29 Thread thsub = new Thread(new ThreadStart(() => 30 { 31 while (true) 32 { 33 try 34 { 35 fs.Check(); 36 } 37 catch (Exception ex) 38 { 39 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " fs.Check() Error! CID=" + CID, ExInfo = ex }); 40 } 41 Thread.Sleep(hour * 60 * 60 * 1000); 42 } 43 })); 44 fs.FeedbackReceived += fs_FeedbackReceived; 45 thsub.Start(); 46 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Open TokenProvider! CID=" + CID }); 47 } 48 catch (Exception ex) 49 { LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " Open TokenProvider Error! CID=" + CID, ExInfo = ex }); } 50 } 51 52 /// <summary> 53 /// 處理失效的Token信息 54 /// </summary> 55 /// <param name="deviceToken"></param> 56 /// <param name="timestamp"></param> 57 private void fs_FeedbackReceived(string deviceToken, DateTime timestamp) 58 { 59 try 60 { 61 p_DeleteToken p = new p_DeleteToken(deviceToken); 62 if (p.ExecutionDelete()) { 63 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token success >> " + deviceToken }); 64 } else { 65 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token error >> " + deviceToken, ExInfo = null }); 66 }; 67 } 68 catch (Exception ex) 69 { 70 LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "fs_FeedbackReceived Error! CID=" + CID, ExInfo = ex }); 71 } 72 } 73 } View Code