APNS IOS 消息推送處理失效的Token


在開發蘋果推送服務時候,要合理的控制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

    /// <summary>
    /// FeedbackService
    /// </summary>
    public class FeedbackService
    {
        public FeedbackService(ApnsConfiguration configuration)
        {
            Configuration = configuration;
        }

        public ApnsConfiguration Configuration { get; private set; }

        public delegate void FeedbackReceivedDelegate(string deviceToken, DateTime timestamp);
        public event FeedbackReceivedDelegate FeedbackReceived;

        public void Check()
        {
            var encoding = Encoding.ASCII;

            var certificate = Configuration.Certificate;

            var certificates = new X509CertificateCollection();
            certificates.Add(certificate);

            var client = new TcpClient(Configuration.FeedbackHost, Configuration.FeedbackPort);

            var stream = new SslStream(client.GetStream(), true,
                (sender, cert, chain, sslErrs) => { return true; },
                (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; });

            stream.AuthenticateAsClient(Configuration.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Tls, false);


            //Set up
            byte[] buffer = new byte[4096];
            int recd = 0;
            var data = new List<byte>();

            //Get the first feedback
            recd = stream.Read(buffer, 0, buffer.Length);

            //Continue while we have results and are not disposing
            while (recd > 0)
            {
                // Add the received data to a list buffer to work with (easier to manipulate)
                for (int i = 0; i < recd; i++)
                    data.Add(buffer[i]);

                //Process each complete notification "packet" available in the buffer
                while (data.Count >= (4 + 2 + 32)) // Minimum size for a valid packet
                {
                    var secondsBuffer = data.GetRange(0, 4).ToArray();
                    var tokenLengthBuffer = data.GetRange(4, 2).ToArray();

                    // Get our seconds since epoch
                    // Check endianness and reverse if needed
                    if (BitConverter.IsLittleEndian)
                        Array.Reverse(secondsBuffer);
                    var seconds = BitConverter.ToInt32(secondsBuffer, 0);

                    //Add seconds since 1970 to that date, in UTC
                    var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);

                    //flag to allow feedback times in UTC or local, but default is local
                    if (!Configuration.FeedbackTimeIsUTC)
                        timestamp = timestamp.ToLocalTime();


                    if (BitConverter.IsLittleEndian)
                        Array.Reverse(tokenLengthBuffer);
                    var tokenLength = BitConverter.ToInt16(tokenLengthBuffer, 0);

                    if (data.Count >= 4 + 2 + tokenLength)
                    {

                        var tokenBuffer = data.GetRange(6, tokenLength).ToArray();
                        // Strings shouldn't care about endian-ness... this shouldn't be reversed
                        //if (BitConverter.IsLittleEndian)
                        //    Array.Reverse (tokenBuffer);
                        var token = BitConverter.ToString(tokenBuffer).Replace("-", "").ToLower().Trim();

                        // Remove what we parsed from the buffer
                        data.RemoveRange(0, 4 + 2 + tokenLength);

                        // Raise the event to the consumer
                        var evt = FeedbackReceived;
                        if (evt != null)
                            evt(token, timestamp);
                    }
                    else
                    {
                        continue;
                    }

                }

                //Read the next feedback
                recd = stream.Read(buffer, 0, buffer.Length);
            }

            try
            {
                stream.Close();
                stream.Dispose();
            }
            catch { }

            try
            {
                client.Client.Shutdown(SocketShutdown.Both);
                client.Client.Dispose();
            }
            catch { }

            try { client.Close(); }
            catch { }
        }
    }

下面是處理邏輯:

    /// <summary>
    /// 處理失效的Token邏輯信息
    /// </summary>
    public class TokenProvider
    {
        private FeedbackService fs = null;
        private int hour = 12;
        private string CID;

        public TokenProvider(ApnsConfiguration cf, string CID)
        {
            this.fs = fs = new FeedbackService(cf);
            this.CID = CID;
            try
            {
                int hour = int.Parse(ConfigurationManager.AppSettings["ManagerTokenHour"]);//Token的控制時間
            }
            catch { hour = 12; }
        }
        
        /// <summary>
        /// 開啟處理失效的Token邏輯信息
        /// </summary>
        /// <param name="cf"></param>
        public void Init()
        {
            try
            {
                Thread thsub = new Thread(new ThreadStart(() =>
                {
                    while (true)
                    {
                        try
                        {
                            fs.Check();
                        }
                        catch (Exception ex)
                        {
                            LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " fs.Check() Error! CID=" + CID, ExInfo = ex });
                        }
                        Thread.Sleep(hour * 60 * 60 * 1000);
                    }
                }));
                fs.FeedbackReceived += fs_FeedbackReceived;
                thsub.Start();
                LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Open TokenProvider! CID=" + CID });
            }
            catch (Exception ex)
            { LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = " Open TokenProvider Error! CID=" + CID, ExInfo = ex }); }
        }

        /// <summary>
        /// 處理失效的Token信息
        /// </summary>
        /// <param name="deviceToken"></param>
        /// <param name="timestamp"></param>
        private void fs_FeedbackReceived(string deviceToken, DateTime timestamp)
        {
            try
            {
                p_DeleteToken p = new p_DeleteToken(deviceToken);
                if (p.ExecutionDelete()) {
                    LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token success >> " + deviceToken });
                } else {
                    LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "Delete lose token error >> " + deviceToken, ExInfo = null });
                };
            }
            catch (Exception ex)
            {
                LogInfoProvider.config.Logs.Add(new LogClass() { LogStr = "fs_FeedbackReceived Error! CID=" + CID, ExInfo = ex });
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM