從蘋果apns的feedback服務器獲取推送失敗的token,apnsfeedback
在開發自己的蘋果推送服務時候,要合理的控制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