本文内容部分来自Parse.com的iOS开发教程,这个是相关的视频讲解

本文下半部分来自https://blog.csdn.net/yydev/article/details/52105830。

正式开始之前的准备工作

我们先来从Apple Developer网站上创建一个关联App ID和开发供应配置文件的SSL证书,来开始这段美好的教程。接着,我们看看在iOS下是如何在解析网站(Parse website)配置解析程序(Parse app)的。最后,我们把这些理论付诸实践,创建一个带有推送功能的App,并且将消息推到用户。

在开始这段美好旅程之前,大家一定要注意iOS模拟器是不支持推送的,因为模拟器暂时没有devicetoken,所以你必须想办法找一台真机过来。还有就是要有苹果开发者协议,之后才能在真机上面进行开发和测试。

创建SSL证书

首先,需要在苹果开发者网站上创建一个App ID以及关联的SSL证书,有了这个证书,解析服务器才能将找到你的App ID,继而将通知推送到该应用。

创建一个证书请求

首先的首先,我们需要有一个证书签名请求文件,之后创建SSL证书才有意义。创建文件的方法如下:

1.在Mac上运行钥匙串访问(keychain)

2.选择钥匙串访问 > 证书助理 > 从证书颁发机构中请求一个证书

3.输入你的名字和邮件地址,CA邮件地址默认就可以,不要试图去进行任何改动。

4.选择“保存到硬盘”,这样就会将刚创建的证书请求文件下载到电脑桌面上了。

创建并调教一个App ID

每个安装在你开发者设备上的iOS程序都需要一个独有的App ID,方便起见,App ID以反向路径规则命名,形如com.parseSampleApp,但是一定要注意App ID里不能包含星号("*")。创建步骤如下:

1.登陆网站Apple Developer Member Center并进入iOS Provisioning Portal

2.从左边栏里点击App IDs。

3.选择New App ID,然后创建一个新的App ID。一定要确保Bundle Identifier一栏中没有星号。

4.在你的App ID下面找到Configure,选中。

5.将“Enable for Apple Push Notification service”勾选上,然后点击Development Push SSL Certificate下面的Configure,然后会出现Apple Push Notification service SSL Certificate Assistant设置向导。

6.点击Continue继续,然后点击Choose File,选中刚创建见的.certSigningRequest文件。

7.点击Generate开始生成,然后点击Download下载生成的SSL证书。

8.通过keychain程序来安装下载好的SSL证书。

9.接着在“我的证书”选项先面,找到你刚才安装名称形如“Apple Development IOS Push Services: xxx”的证书。

10.双击证书,选择“导出”,导出后的文件后缀名为.p12。这个时候千万注意!出现密码提示的时候一定不要添任何东西。

这里值得注意的一点就是,至此我们只是将应用的推送通知功能在开发模式中开启了,所以应用开始正式发布之前,一定记得要将第四步到第九步的流程重新走一遍,并将第五步中的“Development Push SSL Certificate”改成“Production Push SSL Certificate”。这样就完美了。

创建一个Provisioning Profile(配置简介)

Provisioning Profile会验证运行所开发应用的设备。而且不管你是新建一个App ID还是去修改现成的,都得重新生成并安装一遍Provisioning Profile。步骤如下:

1.在iOS Provisioning Portal中选择Provisioning变迁。

2.点击New Profile

3.填好对应的信息,确保一下三项(developer certificate、上面刚创建好的App ID以及用于测试的设备)都没有遗漏,全都选中。

4.点击Actions一栏下面的Download按钮下载生成好的Provisioning Profile。

5.双击下载好的文件,默认是由iPhone Configuration Utility程序开。

配置Parse App

要想在推送通知中使用Parse功能,必须将此项特性设置成开启状态,然后将上面创建好的推送SSL证书上传上去。步骤如下:

1.在Parse website上找到你的Parse app,然后选择Settings标签页。

2.在iOS Push Notification Settings下面,点击Choose File,然后将之前用keychain导出的.p12文件上传上去。

3.如果希望用户能够发送推送通知,我们需要将Client push enabled?选项中的Yes勾选上。这个功能对于像即时聊天的软件非常有用,我们现在将它勾选上,当然开发者需要自行决定是否要开启这项功能。

4.点击Save保存。

至此,所有的前提条件都搞完了,马上进入最激动人心的创建一个具备推送通知应用的环节了,喝口水,开搞。

创建一个具备推送通知的应用

首先,我们需要先对Xcode项目进行一些设置,确保App ID和provisioning profile都被设置成良好的状态。做开发吗,

1.在Supporting Files文件夹下选中ProjectName-Info.plist,对右侧视图中的Bundle Identifier选项进行修改,和你自己创建的App ID保持一致(形如:com.parseSampleApp)。

2.在左侧的菜单中选中刚创建的project文件,在下面找到Build Settings然后搜索Code Signing Identity。

3.将对应provisioning profile的所有的值全部设置好。

4.选择左手边Targets下面的项目名称,再次找到Build Settings,来到Code Signing Identity区域,确保所有的值都和新的provisioning profile保持一致。

代码环节

接下来就开始进入编程模式了。我们需要对应用程序代理(app delegate)进行少量的修改,从而使得我们的应用可以接受到推送通知。步骤如下:

1.注册设备需要在app delegate的[application:didFinishLaunchingWithOptions:]方法中调用[application registerForRemoteNotificationTypes:]方法,代码如下:

  1. - (BOOL)application:(UIApplication *)application
  2. didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  3. {
  4. ...
  5. // Register for push notifications
  6. [application registerForRemoteNotificationTypes:
  7. UIRemoteNotificationTypeBadge |
  8. UIRemoteNotificationTypeAlert |
  9. UIRemoteNotificationTypeSound];
  10. ...
  11. }

2.一旦成功,以上方法会在app delegate中执行回调方法[application:didRegisterForRemoteNotificationsWithDeviceToken:] 。我们需要实现这个方法,用它来告知Parse我们的设备信息。代码如下:

  1. - (void)application:(UIApplication *)application
  2. didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
  3. {
  4. [PFPush storeDeviceToken:newDeviceToken]; // Send parse the device token
  5. // Subscribe this user to the broadcast channel, ""
  6. [PFPush subscribeToChannelInBackground:@"" block:^(BOOL succeeded, NSError *error) {
  7. if (succeeded) {
  8. NSLog(@"Successfully subscribed to the broadcast channel.");
  9. } else {
  10. NSLog(@"Failed to subscribe to the broadcast channel.");
  11. }
  12. }];
  13. }

3.广播频道(broadcast channel)用于同时联系到所有用户,所以很多时候开发者可能需要自己创建一些更精准化的频道。一旦推送通知被接受但是应用不在前台,就会被显示在iOS推送中心。反之如果应用刚好处于活动状态,则交于应用去自行处理。具体我们可以在app delegate中实现[application:didReceiveRemoteNotification]方法。一下示例代码只是简单的将这一需求交由Parse去处理,Parse会创建一个模态警报显示推送内容。

  1. - (void)application:(UIApplication *)application
  2. didReceiveRemoteNotification:(NSDictionary *)userInfo {
  3. [PFPush handlePush:userInfo];
  4. }

好了,现在开始在你的iOS设备上运行一下,一切顺利的话,就可以看到从用户到推送通知之间的一条模态警报请求许可。

发送推送通知

从Parse website发送

Parse允许你从Parse website发送推送通知,API和SDK均可。找到Parse app,选择Push Notifications标签,你可以在文本框里添加一条消息,然后广播给所以用户。你可以使用Parse web API通过发送一个POST请求来发送推送到任何频道。以下示例是一条广播通知,内容是“Hello World”,使用curl进行发送。

  1. curl -X POST "https://api.parse.com/1/push" -H "Content-Type: application/json" \
  2. --data '{"key":"your_push_master_key", "channel":"", "type":"ios",\
  3. "data":{"alert":"Hello World!"}}'

从应用发送

从应用发送需要开启Parse app中的Client push enabled功能。实现从应用发送推送通知的方式多种多样,你可以在iOS API documentation中找到一切。

  1. // Broadcast "Hello World"
  2. [PFPush sendPushMessageToChannelInBackground:@"" withMessage:@"Hello World!"];

iOS10关于推送的新特性, 相比之前确实做了很大的改变,总结起来主要是以下几点:

  1. 推送内容更加丰富,由之前的alert 到现在的title, subtitle, body
  2. 推送统一由trigger触发
  3. 可以为推送增加附件,如图片、音频、视频,这就使推送内容更加丰富多彩
  4. 可以方便的更新推送内容

import 新框架

添加新的框架 UserNotifications.framework 

#import <UserNotifications/UserNotifications.h>

注册推送

在设置通知的时候,需要先进行注册,获取授权 
iOS10 所有通知都是通过UNUserNotificationCenter来管理,包括远程通知和本地通知

   //iOS8以下
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; //iOS8 - iOS10
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]]; //iOS10
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { }

获取用户设置

iOS10 提供了获取用户授权相关设置信息的接口getNotificationSettingsWithCompletionHandler: , 回调带有一个UNNotificationSettings对象,它具有以下属性,可以准确获取各种授权信息

authorizationStatus
soundSetting
badgeSetting
alertSetting
notificationCenterSetting
lockScreenSetting
carPlaySetting
alertStyle

像下面的方法,点击allow 

    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
//点击允许
NSLog(@"注册通知成功");
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"%@", settings);
}];
} else {
//点击不允许
NSLog(@"注册通知失败");
}
}]; 打印信息: *<UNNotificationSettings: 0x174090a90; authorizationStatus: Authorized, notificationCenterSetting: Enabled, soundSetting: Enabled, badgeSetting: Enabled, lockScreenSetting: Enabled, alertSetting: NotSupported, carPlaySetting: Enabled, alertStyle: Banner>*

注册APNS, 获取token

iOS10, 注册APNS和获取token的方法还和之前一样 
application: didFinishLaunchingWithOptions:调用 registerForRemoteNotifications方法

[[UIApplication sharedApplication] registerForRemoteNotifications];

在代理方法application: didRegisterForRemoteNotificationsWithDeviceToken:中获取token

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken NS_AVAILABLE_IOS(3_0){
NSLog(@"deviceToken:%@",deviceToken);
} - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error NS_AVAILABLE_IOS(3_0){
NSLog(@"didFailToRegisterForRemoteNotificationsWithError:%@",error);
}

设置处理通知的action 和 category

在iOS8以前是没有category这个属性的; 
在iOS8注册推送,获取授权的时候,可以一并设置category, 注册的方法直接带有这个参数; 
在iOS10, 需要调用一个方法setNotificationCategories:来为管理推送的UNUserNotificationCenter实例设置category, category又可以对应设置action;

//设置category
//UNNotificationActionOptionAuthenticationRequired 需要解锁
//UNNotificationActionOptionDestructive 显示为红色
//UNNotificationActionOptionForeground 点击打开app UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"action1" title:@"策略1行为1" options:UNNotificationActionOptionForeground]; UNTextInputNotificationAction *action2 = [UNTextInputNotificationAction actionWithIdentifier:@"action2" title:@"策略1行为2" options:UNNotificationActionOptionDestructive textInputButtonTitle:@"comment" textInputPlaceholder:@"reply"]; //UNNotificationCategoryOptionNone
//UNNotificationCategoryOptionCustomDismissAction 清除通知被触发会走通知的代理方法
//UNNotificationCategoryOptionAllowInCarPlay 适用于行车模式
UNNotificationCategory *category1 = [UNNotificationCategory categoryWithIdentifier:@"category1" actions:@[action2,action1] minimalActions:@[action2,action1] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction]; UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"action3" title:@"策略2行为1" options:UNNotificationActionOptionForeground]; UNNotificationAction *action4 = [UNNotificationAction actionWithIdentifier:@"action4" title:@"策略2行为2" options:UNNotificationActionOptionForeground];
UNNotificationCategory *category2 = [UNNotificationCategory categoryWithIdentifier:@"category2" actions:@[action3,action4] minimalActions:@[action3,action4] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction]; [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObjects:category1,category2, nil]];

设置通知内容

因为iOS10远程通知与本地通知统一起来了,通知内容属性是一致的,不过远程推送就需要在payload进行具体设置了,下面以本地通知为例,介绍关于UNNotificationContent的内容 
官网上明确说明了,我们是不能直接创建UNNotificationContent的实例的, 如果我们需要自己去配置内容的各个属性,我们需要用到UNMutableNotificationContent 
看一下它的一些属性:

attachments          //附件
badge //徽标
body //推送内容body
categoryIdentifier //category标识
launchImageName //点击通知进入应用的启动图
sound //声音
subtitle //推送内容子标题
title //推送内容标题
userInfo //远程通知内容 UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"Test";
content.subtitle = @"1234567890";
content.body = @"Copyright © 2016年 jpush. All rights reserved.";
content.badge = @1;
NSError *error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:@"718835727" ofType:@"png"];
UNNotificationAttachment *att = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
if (error) {
NSLog(@"attachment error %@", error);
}
content.attachments = @[att];
content.categoryIdentifier = @"category1”; //这里设置category1, 是与之前设置的category对应
content.launchImageName = @"1-Eb_0OvtcxJXHZ7-IOoBsaQ"; UNNotificationSound *sound = [UNNotificationSound defaultSound];
content.sound = sound;

通知触发器

UNNotificationTrigger 
iOS 10触发器有4种

  • UNPushNotificationTrigger 触发APNS服务,系统自动设置(这是区分本地通知和远程通知的标识)
  • UNTimeIntervalNotificationTrigger 一段时间后触发
  • UNCalendarNotificationTrigger 指定日期触发
  • UNLocationNotificationTrigger 根据位置触发,支持进入某地或者离开某地或者都有

    //十秒后
    UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO]; //每周日早上8:00
    NSDateComponents *component = [[NSDateComponents alloc] init];
    component.weekday = 1;
    component.hour = 8;
    UNCalendarNotificationTrigger *trigger2 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:component repeats:YES]; //圆形区域,进入时候进行通知
    CLLocationCoordinate2D cen = CLLocationCoordinate2DMake(80.335400, -90.009201);
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:cen
    radius:500.0 identifier:@“center"];
    region.notifyOnEntry = YES; //进入的时候
    region.notifyOnExit = NO; //出去的时候
    UNLocationNotificationTrigger *trigger3 = [UNLocationNotificationTrigger
    triggerWithRegion:region repeats:NO];

添加通知 / 更新通知

  1. 创建一个UNNotificationRequest类的实例,一定要为它设置identifier, 在后面的查找,更新, 删除通知,这个标识是可以用来区分这个通知与其他通知
  2. 把request加到UNUserNotificationCenter, 并设置触发器,等待触发
  3. 如果另一个request具有和之前request相同的标识,不同的内容, 可以达到更新通知的目的

       NSString *requestIdentifer = @"TestRequest";
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifer content:content trigger:trigger1];
    //把通知加到UNUserNotificationCenter, 到指定触发点会被触发
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    }]; //在另外需要更新通知的地方
    UNMutableNotificationContent *newContent = [[UNMutableNotificationContent alloc] init];
    newContent.title = @"Update";
    newContent.subtitle = @"XXXXXXXXX";
    newContent.body = @"Copyright © 2016年 jpush. All rights reserved.";
    UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:3 repeats:NO];
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"TestRequest" content:newContent trigger:trigger1];
    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { }];

获取和删除通知

这里通知是有两种状态

  • Pending 等待触发的通知
  • Delivered 已经触发展示在通知中心的通知

    //获取未触发的通知
    [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
    NSLog(@"pending: %@", requests);
    }]; //获取通知中心列表的通知
    [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
    NSLog(@"Delivered: %@", notifications);
    }]; //清除某一个未触发的通知
    [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[@"TestRequest1"]];
    //清除某一个通知中心的通知
    [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[@"TestRequest2"]];
    //对应的删除所有通知
    [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
    [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];

delegate

<UNUserNotificationCenterDelegate>

iOS10收到通知不再是在application: didReceiveRemoteNotification:方法去处理, iOS10推出新的代理方法,接收和处理各类通知(本地或者远程)

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
//应用在前台收到通知
NSLog(@"========%@", notification);
} - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
//点击通知进入应用
NSLog(@"response:%@", response);
}

最后

下一篇文章继续介绍关于富媒体推送的 UNNotificationServiceExtension 和 Notification content extension

iOS10 关于推送-b的更多相关文章

  1. iOS10 远程推送代码 以及服务器端代码(.net)

    // // AppDelegate.m // MyPushDemo // // Created by justapple on 16/12/25. // Copyright © 2016年 dengq ...

  2. iOS10全新推送功能的实现

    从iOS8.0开始推送功能的实现在不断改变,功能也在不断增加,iOS10又出来了一个推送插件的开发(见最后图),废话不多说直接上代码: 在开始之前需要打开一个推送开关,不然无法获取deviceToke ...

  3. SwiftUI - iOS10本地推送通知教程UserNotifications在Swift中的实现方式

    简介 消息推送相信在很多人的眼里都不陌生了吧?像即时聊天微信,好友发信息给你时会在顶部弹下小窗口提醒你.也像是在影院APP预订了电影票,在开场前一小时你也会收到提醒.这类推送是需要经过后端发送请求的, ...

  4. iOS10 远程推送服务器所需证书以及应用授权文件配置

    推送证书制作步骤(目的:导出服务器需要的p12证书) 第一步: 打开Mac系统的"钥匙串访问"-"证书助理"-"从证书颁发机构请求证书" 取 ...

  5. iOS开发 iOS10推送必看(基础篇)

    iOS10更新之后,推送也是做了一些小小的修改,下面我就给大家仔细说说.希望看完我的这篇文章,对大家有所帮助.   原文链接   一.简单入门篇---看完就可以简单适配完了相对简单的推送证书以及环境的 ...

  6. iOS开发 iOS10推送必看

    iOS10更新之后,推送也是做了一些小小的修改,下面我就给大家仔细说说.希望看完我的这篇文章,对大家有所帮助. 一.简单入门篇---看完就可以简单适配完了 相对简单的推送证书以及环境的问题,我就不在这 ...

  7. iOS10 推送通知 UserNotifications

    简介 新框架 获取权限 获取用户设置 注册APNS,获取deviceToken 本地推送流程 远程推送流程 通知策略(Category+Action) 附件通知 代理回调 简介 iOS10新增了Use ...

  8. iOS开发 iOS10推送必看(基础篇)-转

    iOS10更新之后,推送也是做了一些小小的修改,下面我就给大家仔细说说.希望看完我的这篇文章,对大家有所帮助. 一.简单入门篇---看完就可以简单适配完了 相对简单的推送证书以及环境的问题,我就不在这 ...

  9. iOS---iOS10适配iOS当前所有系统的远程推送

    一.iOS推送通知简介 众所周知苹果的推送通知从iOS3开始出现, 每一年都会更新一些新的用法. 譬如iOS7出现的Silent remote notifications(远程静默推送), iOS8出 ...

随机推荐

  1. MongoDB - Introduction to MongoDB, MongoDB Extended JSON

    JSON can only represent a subset of the types supported by BSON. To preserve type information, Mongo ...

  2. .NET DLL 保护措施详解(五)常规条件下的破解

    为了证实在常规手段破解下能有效保护程序核心功能(演示版本对AES加解密算法及数据库的密钥(一段字符串)进行了保护),特对此DLL保护思路进行相应的测试,包含了反编译及反射测试,看是否能得到AES加解密 ...

  3. ASP.NET缓存全解析3:页面局部缓存 转自网络原文作者李天平

    有时缓存整个页面是不现实的,因为页的某些部分可能在每次请求时都需要变化.在这些情况下,只能缓存页的一部分.顾名思义,页面部分缓存是将页面部分内容保存在内存中以便响应用户请求,而页面其他部分内容则为动态 ...

  4. Android文字转语音

    虽然视觉上的反馈通常是给用户提供信息最快的方式,但这要求用户把注意力设备上.当用户不能查看设备时,则需要一些其他通信的方法.Android提供了强大的文字转语音Text-to-Speech,TTS A ...

  5. shell获取本地ip的三种方法

    第一种方法:ifconfig|grep inet |awk '{print $2}'|sed '2d'|awk -F : '{print $2}'第二种方法:ifconfig|grep inet|se ...

  6. JAVA 模糊查询方法

    当我们需要开发一个方法用来查询数据库的时候,往往会遇到这样一个问题:就是不知道用户到底会输入什么条件,那么怎么样处理sql语句才能让我们开发的方法不管接受到什么样的条件都可以正常工作呢?这时where ...

  7. Java关键字介绍之this与super

    1.什么是super?什么是this? super关键字表示超(父)类的意思.this变量代表对象本身. 2.使用super&this调用成员变量和方法 可以使用super访问父类被子类隐藏的 ...

  8. ubuntu 常用参数设置

        在Linux下,对于参数的设置,一般来说,都遵循这个规律.每一个功能程序,一定对于一个对于名字的配置文件.     涉及到多用户的功能配置,一定有一个全局的配置文件,对所有用户都生效,而每个用 ...

  9. how to debug thread cpu 100%

    when we write a program, cpu and memory usages are very important to indicate the stability of the p ...

  10. linux远程客户端putty,xshell搭建注意事项——《视频》

    本视频放在云端,点击此链接即可播放:              http://www.tudou.com/programs/view/75QMh0-DQfA/               崇尚开源,热 ...