iOS 远端推送部署详解

最近几天被iOS的推送部署给搞懵了,现在特地整理下和大家进行分享。 iOS远端推送机制 APNS,全称为Apple Push Notification service,是苹果通知推送服务中最重要的一环。它是苹果通知推送服务器,为所有iOS设备以及OS X设备提供强大并且可靠的推送通知服务。每个注册通知服务的设备都会和该服务器进行长连接,从而实时获取推送通知。即使当前APP不在运行状态,当通知到达的时候也会有提示发生,最常见的就是短信服务。 每一个App必须向APNs注册通知服务,APNs会返回给设备一个DeviceToken,该Token为APNs上针对该设备的唯一标示符。App需要将该DeviceToken返给自身的Server端保存后续使用,如下所示。 当App开发者的server需要向特定设备推送通知时,就使用DeviceToken和固定格式数据(Push payload)发给APNs,然后APNs就会向DeviceToken指定的设备推送通知了,具体流程如下所示,单一推送 或者多方通知,APNs都能一一对应,靠的就是之前我们提供给它的DeviceToken。 本地推送证书配置 打开你mac的钥匙串访问,然后点击钥匙串访问 随后它会弹出一个窗口 用户电子邮件信息 就填写你苹果开发者账号的名称即可(应该是一个邮件名称),点击保存到磁盘的选项,点击继续,点击存储,文件名为:CertificateSigningRequest.certSigningRequest。 然后我们打开苹果开发者中心 进入 Member Center 然后点击左侧列表中任意一项进入详情页面, APP ID 首先我们需要为我们要开发的APP建立身份信息,就是AppID,如图所示,点击左侧 点击添加按钮进入注册页面,我们需要输入App Id的名字以及BundleID,其中BundleID不能有通配符,否则无法具备推送功能,然后在下面的APP Service中勾选Push Notification一项 点击下一步,然后确认提交即可,大家注意到Push Notification一项为Configurable,这是因为我们还没有为该AppID生成推送证书,等推送证书生成完毕之后可以再回来查看该AppID 的状态。 Certificates 其次,我们需要生成开发者证书和推送证书,如下图所示,点击左侧Cerifications列表,选择添加进入下一页面, 如果您的页面如图所示为灰色不可选,说明您已经拥有了开发者证书。就不需要再次生成了,如果可选就选择该选项, 接下来进入以下界面,选择你之前添加的AppID,之后点击Continue即可, 然后选择之前我们保存在本地的CSR文件CertificateSigningRequest.certSigningRequest,点击Generate就生成了开发者的证书。 同理我们需要生成推送测试证书,生成流程和开发者证书类似,只是在证书类型页面,选择的证书类型换成了Apple Push Notification service SSL。 当我们生成好推送证书之后再回头看我们之前创建的AppId,能够看Push Notifications一项已经为Enabled了。当然发布推送证书配置完毕之后,Distribution一项也显示为Enable。 Provisioning Profiles 第三步,需要生成Provisioning Profiles,该文件其实就是以上的证书、AppId以及设备信息的打包集合,我们只要在不同的场景下生成不同类型Provisioning Profiles即可,它会在后续打包ipa文件的时候被嵌入安装包内。 ...

July 30, 2015 · 3 min · Chen He

关于单链表的那些事儿

关于有环单链表,即单链表中存在环路,该问题衍生出很多面试题,特在此汇总,方便查阅也帮助自己梳理下思路。 如下图1所示为有环单链表,假设头结点为H, 环的入口点为A。 关于有环单链表相关的问题: 该单链表中是否真有环存在? 如何求出环状的入口点? 如何求出环状的长度? 求解整条链表的长度? 下面我们分别针对这几个问题进行分析和解答。 判断一个单链表是否存在环 首先,关于第一个问题,如何确定一条链表中确实存在环,关于环状的检测主要有三种方法,链表环状检测主要有三种方法:外部记录法,内部记录法以及追赶法。 内部标记法和外部标记法其实是一个道理,不过就是辅助变量一个是在链表节点内,一个是借助辅助数组或者hash或者AVL,红黑树等 把已经访问过的节点地址存起来,每次访问下一个节点的时候进行查询看是否已经出现过。这里不再赘述。主要看追赶法,也称快满指针法,而追赶法大家一定都已经烂熟于心了。 追赶法主要利用最大公倍数原理,用2个游标,对链表进行访问,例如:pSlow, pFast。 pSlow访问每步向前进1个节点,而pFast则每次向前前进2个节点,如果有环则pSlow和pFast必会相遇,如果pFast最终指向了NULL,则说明该链表不存在环路。因为两个指针步子迈的不一样,因为被称作快慢指针。 // Definition for singly - linked list. struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {} }; bool isLoopList(ListNode *pHead){ if (nullptr == pHead || nullptr == pHead->next){ return false; } ListNode *pSlow = pHead; ListNode *pFast = pHead; while (pFast && pFast->next){ pFast = pFast->next->next; pSlow = pSlow->next; if (pFast == pSlow){ break; } } return !(nullptr == pFast || nullptr == pFast->next); } 确定该有环单链表的环的入口 关于这个问题,首先我们需要证明当pSlow和pFast第一次相遇的时候,pSlow并未走完整个链表或者恰好到达环入口点。 看上图(画的比较粗糙),假设 pSlow 到达环状入口点A的时候,pFast在环上某一点B,假设B逆时针方向离 A 点距离为 y ,并且整个环状的长度为R,我们知道y <= R。从A点开始,pSlow向前走y步,此时pFast从点B往前则走 2 * y 步 并与 pSlow 相遇于点 D,此时pSlow还需R - y 才能到达链表尾端,也即A点。因为y <= R,因此R - y >= 0。得证。 ...

May 7, 2015 · 2 min · Chen He

[151] Reverse Words in a String

题目:Reverse Words in a String Given an input string s, reverse the string word by word. For example, given s = “the sky is blue”, return “blue is sky the”. 题意: 题意很明确,将字符串中的单词进行翻转,形成新的字符串。但是这其中有几个问题我们需要思考(参考leetCode官方CleanCodeBook): Q: What constitutes a word? A: A sequence of non-space characters constitutes a word. Q: Does tab or newline character count as space characters? A: Assume the input does not contain any tabs or newline characters. Q: Could the input string contain leading or trailing spaces? A: Yes. However, your reversed string should not contain leading or trailing spaces. ...

May 1, 2015 · 1 min · Chen He

Two Sum

本文主要包括 leetCode 题集里的两个题目,Two Sum1 和 Two Sum2 题目1: 1. Two Sum 1 Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based. You may assume that each input would have exactly one solution. ...

April 29, 2015 · 2 min · Chen He

[160] Intersection of Two Linked Lists

题目:Intersection of Two Linked lists Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists: A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3 begin to intersect at node c1. Notes: 1. If the two linked lists have no intersection at all, return null. 2. The linked lists must retain their original structure after the function returns. 3. You may assume there are no cycles anywhere in the entire linked structure. 4. Your code should preferably run in O(n) time and use only O(1) memory ...

April 29, 2015 · 3 min · Chen He

关于Lambda的一点梳理

关于C++11的新特性,最近接触比较多的就是关于thread的部分,还有就是Lambda表达式,今天主要针对Lambda的用法进行一定的阐述和汇总(参考链接在文章下方,向大师致敬!),同时给自己梳理下知识点,加深印象。 基本的Lambda表达式如下所示,该表达式计算一个整型数据的平方值并返回,并且该表达式能够直接使用,是不是特别方便?不再需要将类本身和函数定义分割开来。 int result = [](int input){ return input * input; }(10); std::cout << result << std::endl; 如果你需要重用该段代码片段,可以将该函数保存为本地变量,如下所示: auto func = [](int input){ return input * input; }; std::cout << func(10) << std::endl; std::cout << func(20) << std::endl; 好了,现在我们需要写一个能够计算浮点类型的Lambda表达式怎么办? 或者我们需要能够计算复数(complex number)怎么办? 我们需要的就像下面这样: // int 的平方 std::cout << func(10) << std::endl; // double的平方 std::cout << func(3.1415) << std::endl; // 复数的平方 std::cout << func(std::complex<double>(3, -2)) << std::endl; 如何让代码复用起来? 当然是 函数模板(function template)了。 如下: template <typename T> T func(T param) { return param * param; } 但是函数模板并不是那篇文章所追求的,以上的这段代码被称作是 a named global function. 而在最新的通过的C++14标准中引入了 generalized lambda的概念。我们允许lambda表达式的传参类型为auto类型(看来C++是要强化类型自动推导啊,auto关键字能够使用的地方越来越多了。),如下我们能够使用更短,更优雅的代码实现以上需求。 auto func = [](auto input){ return input * input; }; 完整代码如下: #include<iostream> #include<complex> int main() { // Store a generalized lambda, that squares a number, in a variable auto func = [](auto input) { return input * input; }; // Usage examples: // square of an int std::cout << func(10) << std::endl; // square of a double std::cout << func(2.345) << std::endl; // square of a complex number std::cout << func(std::complex<double>(3, -2)) << std::endl; return 0; } 其实lambda表达式和STL在一起使用能够发挥很大的作用,假设你要排序一个vector让其降序,使用generic lambda,我们可以这样写: ...

April 29, 2015 · 2 min · Chen He