标签:
iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录、微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等。今天将和大家一起学习如何使用系统应用、使用系统服务。
在开发某些应用时可能希望能够调用iOS系统内置的电话、短信、邮件、浏览器应用,此时你可以直接使用UIApplication的OpenURL:方法指定特定的协议来打开不同的系统应用。
常用的协议如下:
(1)打电话:tel:或者tel://、telprompt:或telprompt://(拨打电话前有提示)
(2)发短信:sms:或者sms://
(3)发送邮件:mailto:或者mailto://
(4)启动浏览器:http:或者http://
代码示例:
1 #import "ViewController.h" 2 3 @interface ViewController () 4 @property(nonatomic,strong) UIButton *callButton; 5 @property(nonatomic,strong) UIButton *sendMessageButton; 6 @property(nonatomic,strong) UIButton *sendEmailButton; 7 @property(nonatomic,strong) UIButton *broweerButton; 8 @end 9 10 @implementation ViewController 11 - (UIButton *)callButton{ 12 if (!_callButton) { 13 self.callButton = [UIButton buttonWithType:UIButtonTypeCustom]; 14 _callButton.frame = CGRectMake(100, 50, 100, 20); 15 [_callButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 16 [_callButton setTitle:@"打电话" forState:UIControlStateNormal]; 17 [_callButton addTarget:self action:@selector(callButtonAction) forControlEvents:UIControlEventTouchUpInside]; 18 } 19 return _callButton; 20 } 21 - (UIButton *)sendMessageButton{ 22 if (!_sendMessageButton) { 23 self.sendMessageButton = [UIButton buttonWithType:UIButtonTypeCustom]; 24 _sendMessageButton.frame = CGRectMake(100, 100, 100, 20); 25 [_sendMessageButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 26 [_sendMessageButton setTitle:@"发信息" forState:UIControlStateNormal]; 27 [_sendMessageButton addTarget:self action:@selector(sendMessageButtonAction) forControlEvents:UIControlEventTouchUpInside]; 28 } 29 return _sendMessageButton; 30 } 31 - (UIButton *)sendEmailButton{ 32 if (!_sendEmailButton) { 33 self.sendEmailButton = [UIButton buttonWithType:UIButtonTypeCustom]; 34 _sendEmailButton.frame = CGRectMake(100, 150, 100, 20); 35 [_sendEmailButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 36 [_sendEmailButton setTitle:@"发邮件" forState:UIControlStateNormal]; 37 [_sendEmailButton addTarget:self action:@selector(sendEmailButtonAction) forControlEvents:UIControlEventTouchUpInside]; 38 } 39 return _sendEmailButton; 40 } 41 - (UIButton *)broweerButton{ 42 if (!_broweerButton) { 43 self.broweerButton = [UIButton buttonWithType:UIButtonTypeCustom]; 44 _broweerButton.frame = CGRectMake(100, 200, 100, 20); 45 [_broweerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 46 [_broweerButton setTitle:@"浏览网页" forState:UIControlStateNormal]; 47 [_broweerButton addTarget:self action:@selector(broweerButtonAction) forControlEvents:UIControlEventTouchUpInside]; 48 } 49 return _broweerButton; 50 } 51 52 - (void)viewDidLoad { 53 [super viewDidLoad]; 54 [self.view addSubview:self.callButton]; 55 [self.view addSubview:self.sendMessageButton]; 56 [self.view addSubview:self.sendEmailButton]; 57 [self.view addSubview:self.broweerButton]; 58 } 59 60 #pragma mark - 打电话 61 - (void)callButtonAction{ 62 // 这种方式会提示用户确认是否拨打电话 63 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"telprompt://%@",@"13633726726"]]; 64 65 // 这种方式会直接拨打电话 66 // NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",@"13633726726"]]; 67 [self openUrl:url]; 68 } 69 #pragma mark - 发短信 70 - (void)sendMessageButtonAction{ 71 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"sms://%@",@"13633726726"]]; 72 [self openUrl:url]; 73 } 74 #pragma mark - 发邮件 75 - (void)sendEmailButtonAction{ 76 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"mailto://%@",@"13673527680@163.com"]]; 77 [self openUrl:url]; 78 } 79 #pragma mark - 浏览网页 80 - (void)broweerButtonAction{ 81 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.baidu.com"]]; 82 [self openUrl:url]; 83 } 84 85 #pragma mark - 打开应用方法 86 - (void)openUrl:(NSURL *)url{ 87 // 注意url中包含协议名称,iOS根据协议确定调用哪个应用,例如发送邮件是“sms://”其中“//”可以省略写成“sms:”(其他协议也是如此) 88 UIApplication *application = [UIApplication sharedApplication]; 89 if ([application canOpenURL:url]) { 90 [application openURL:url]; 91 }else{ 92 NSLog(@"无法打开\"%@\"",url); 93 } 94 95 } 96 @end
注意:打开系统应用在模拟器上没办法使用,使用真机有效果。
不难发现当openURL:方法只要指定一个URL Scheme并且已经安装了对应的应用程序就可以打开此应用。当然,如果是自己开发的应用也可以调用openURL方法来打开。假设你现在开发了一个应用A,如果用户机器上已经安装了此应用,并且在应用B中希望能够直接打开A。那么首先需要确保应用A已经配置了Url Types,具体方法就是在plist文件中添加URL types节点并配置URL Schemas作为具体协议,配置URL identifier作为这个URL的唯一标识,如下图:
然后就可以调用openURL方法像打开系统应用一样打开第三方应用程序了:
1 //打开第三方应用 2 - (IBAction)thirdPartyApplicationClick:(UIButton *)sender { 3 NSString *url=@"cmj://myparams"; 4 [self openUrl:url]; 5 }
就像调用系统应用一样,协议后面可以传递一些参数(例如上面传递的myparams),这样一来在应用中可以在AppDelegate的-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation代理方法中接收参数并解析:
1 -(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ 2 NSString *str=[NSString stringWithFormat:@"url:%@,source application:%@,params:%@",url,sourceApplication,[url host]]; 3 NSLog(@"%@",str); 4 return YES;//是否打开 5 }
1.iOS开发中如何跳到系统设置里的各种设置界面:
(1)定位服务
定位服务有很多APP都有,如果用户关闭了定位,那么,我们在APP里面可以提示用户打开定位服务。点击到设置界面设置,直接跳到定位服务设置界面。
代码如下:
1 //定位服务设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=LOCATION_SERVICES"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url]) 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
(2)FaceTime
1 //FaceTime设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=FACETIME"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url]) 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
(3)音乐
1 //音乐设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=MUSIC"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url]) 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
(4)墙纸设置界面
1 //墙纸设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=Wallpaper"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url]) 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
(5)蓝牙设置界面
1 //蓝牙设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=Bluetooth"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url]) 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
(6)iCloud设置界面
1 //iCloud设置界面 2 NSURL *url = [NSURL URLWithString:@"prefs:root=CASTLE"]; 3 if ([[UIApplication sharedApplication] canOpenURL:url] 4 { 5 [[UIApplication sharedApplication] openURL:url]; 6 }
2.参数配置
看到这几个例子,大家有没有发现,想跳到哪个设置界面只需要prefs:root=后面的值即可!是的,就是这样的。
我在网上找到一个列表,可以跳到这些界面的参数配置:
1 About — prefs:root=General&path=About 2 Accessibility — prefs:root=General&path=ACCESSIBILITY 3 Airplane Mode On — prefs:root=AIRPLANE_MODE 4 Auto-Lock — prefs:root=General&path=AUTOLOCK 5 Brightness — prefs:root=Brightness 6 Bluetooth — prefs:root=General&path=Bluetooth 7 Date & Time — prefs:root=General&path=DATE_AND_TIME 8 FaceTime — prefs:root=FACETIME 9 General — prefs:root=General 10 Keyboard — prefs:root=General&path=Keyboard 11 iCloud — prefs:root=CASTLE 12 iCloud Storage & Backup — prefs:root=CASTLE&path=STORAGE_AND_BACKUP 13 International — prefs:root=General&path=INTERNATIONAL 14 Location Services — prefs:root=LOCATION_SERVICES 15 Music — prefs:root=MUSIC 16 Music Equalizer — prefs:root=MUSIC&path=EQ 17 Music Volume Limit — prefs:root=MUSIC&path=VolumeLimit 18 Network — prefs:root=General&path=Network 19 Nike + iPod — prefs:root=NIKE_PLUS_IPOD 20 Notes — prefs:root=NOTES 21 Notification — prefs:root=NOTIFICATIONS_ID 22 Phone — prefs:root=Phone 23 Photos — prefs:root=Photos 24 Profile — prefs:root=General&path=ManagedConfigurationList 25 Reset — prefs:root=General&path=Reset 26 Safari — prefs:root=Safari 27 Siri — prefs:root=General&path=Assistant 28 Sounds — prefs:root=Sounds 29 Software Update — prefs:root=General&path=SOFTWARE_UPDATE_LINK 30 Store — prefs:root=STORE 31 Twitter — prefs:root=TWITTER 32 Usage — prefs:root=General&path=USAGE 33 VPN — prefs:root=General&path=Network/VPN 34 Wallpaper — prefs:root=Wallpaper 35 Wi-Fi — prefs:root=WIFI
1.短信与邮件
调用系统内置的应用来发送短信、邮件相当简单,但是这么操作也存在着一些弊端:当你点击了发送短信(或邮件)操作之后直接启动了系统的短信(或邮件)应用程序,我们的应用其实此时已经处于一种挂起状态,发送完(短信或邮件)之后无法自动回到应用界面。
如果想要在应用程序内部完成这些操作则可以利用iOS中的MessageUI.framework,它提供了关于短信和邮件的UI接口供开发者在应用程序内部调用。从框架名称不难看出这是一套UI接口,提供有现成的短信和邮件的编辑界面,开发人员只需要通过编程的方式给短信和邮件控制器设置对应的参数即可。
在MessageUI.framework中主要有两个控制器类分别用于发送短信(MFMessageComposeViewController)和邮件(MFMailComposeViewController),它们均继承于UINavigationController。由于两个类使用方法十分类似,这里主要介绍一下MFMessageComposeViewController使用步骤:
(1)创建MFMessageComposeViewController对象。
(2)设置收件人recipients、信息正文body,如果运行商支持主题和附件的话可以设置主题subject、附件attachments(可以通过canSendSubject、canSendAttachments方法判断是否支持)
(3)设置代理messageComposeDelegate(注意这里不是delegate属性,因为delegate属性已经留给UINavigationController,MFMessageComposeViewController没有覆盖此属性而是重新定义了一个代理),实现代理方法获得发送状态。
下面自定义一个发送短信的界面演示MFMessageComposeViewController的使用:
用户通过在此界面输入短信信息点击“发送信息”调用MFMessageComposeViewController界面来展示或进一步编辑信息,点击MFMessageComposeViewController中的“发送”来完成短信发送工作,当然用户也可能点击“取消”按钮回到前一个短信编辑页面。
代码示例:
1 #import "KCSendMessageViewController.h" 2 #import <MessageUI/MessageUI.h> 3 4 @interface KCSendMessageViewController ()<MFMessageComposeViewControllerDelegate> 5 6 @property (weak, nonatomic) IBOutlet UITextField *receivers; 7 @property (weak, nonatomic) IBOutlet UITextField *body; 8 @property (weak, nonatomic) IBOutlet UITextField *subject; 9 @property (weak, nonatomic) IBOutlet UITextField *attachments; 10 11 @end 12 13 @implementation KCSendMessageViewController 14 #pragma mark - 控制器视图方法 15 - (void)viewDidLoad { 16 [super viewDidLoad]; 17 18 } 19 20 21 #pragma mark - UI事件 22 - (IBAction)sendMessageClick:(UIButton *)sender { 23 //如果能发送文本信息 24 if([MFMessageComposeViewController canSendText]){ 25 MFMessageComposeViewController *messageController=[[MFMessageComposeViewController alloc]init]; 26 //收件人 27 messageController.recipients=[self.receivers.text componentsSeparatedByString:@","]; 28 //信息正文 29 messageController.body=self.body.text; 30 //设置代理,注意这里不是delegate而是messageComposeDelegate 31 messageController.messageComposeDelegate=self; 32 //如果运行商支持主题 33 if([MFMessageComposeViewController canSendSubject]){ 34 messageController.subject=self.subject.text; 35 } 36 //如果运行商支持附件 37 if ([MFMessageComposeViewController canSendAttachments]) { 38 /*第一种方法*/ 39 //messageController.attachments=...; 40 41 /*第二种方法*/ 42 NSArray *attachments= [self.attachments.text componentsSeparatedByString:@","]; 43 if (attachments.count>0) { 44 [attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 45 NSString *path=[[NSBundle mainBundle]pathForResource:obj ofType:nil]; 46 NSURL *url=[NSURL fileURLWithPath:path]; 47 [messageController addAttachmentURL:url withAlternateFilename:obj]; 48 }]; 49 } 50 51 /*第三种方法*/ 52 // NSString *path=[[NSBundle mainBundle]pathForResource:@"photo.jpg" ofType:nil]; 53 // NSURL *url=[NSURL fileURLWithPath:path]; 54 // NSData *data=[NSData dataWithContentsOfURL:url]; 55 /** 56 * attatchData:文件数据 57 * uti:统一类型标识,标识具体文件类型,详情查看:帮助文档中System-Declared Uniform Type Identifiers 58 * fileName:展现给用户看的文件名称 59 */ 60 // [messageController addAttachmentData:data typeIdentifier:@"public.image" filename:@"photo.jpg"]; 61 } 62 [self presentViewController:messageController animated:YES completion:nil]; 63 } 64 } 65 66 #pragma mark - MFMessageComposeViewController代理方法 67 //发送完成,不管成功与否 68 -(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{ 69 switch (result) { 70 case MessageComposeResultSent: 71 NSLog(@"发送成功."); 72 break; 73 case MessageComposeResultCancelled: 74 NSLog(@"取消发送."); 75 break; 76 default: 77 NSLog(@"发送失败."); 78 break; 79 } 80 [self dismissViewControllerAnimated:YES completion:nil]; 81 } 82 83 @end
这里需要强调一下:
(1)MFMessageComposeViewController的代理不是通过delegate属性指定的而是通过messageComposeDelegate指定的。
(2)可以通过几种方式来指定发送的附件,在这个过程中请务必指定文件的后缀,否则在发送后无法正确识别文件类别(例如如果发送的是一张jpg图片,在发送后无法正确查看图片)。
(3)无论发送成功与否代理方法-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result都会执行,通过代理参数中的result来获得发送状态。
其实只要熟悉了MFMessageComposeViewController之后,那么用于发送邮件的MFMailComposeViewController用法和步骤完全一致,只是功能不同。下面看一下MFMailComposeViewController的使用。
代码示例:
1 #import "KCSendEmailViewController.h" 2 #import <MessageUI/MessageUI.h> 3 4 @interface KCSendEmailViewController ()<MFMailComposeViewControllerDelegate> 5 @property (weak, nonatomic) IBOutlet UITextField *toTecipients;//收件人 6 @property (weak, nonatomic) IBOutlet UITextField *ccRecipients;//抄送人 7 @property (weak, nonatomic) IBOutlet UITextField *bccRecipients;//密送人 8 @property (weak, nonatomic) IBOutlet UITextField *subject; //主题 9 @property (weak, nonatomic) IBOutlet UITextField *body;//正文 10 @property (weak, nonatomic) IBOutlet UITextField *attachments;//附件 11 12 @end 13 14 @implementation KCSendEmailViewController 15 16 - (void)viewDidLoad { 17 [super viewDidLoad]; 18 } 19 20 #pragma mark - UI事件 21 22 - (IBAction)sendEmailClick:(UIButton *)sender { 23 //判断当前是否能够发送邮件 24 if ([MFMailComposeViewController canSendMail]) { 25 MFMailComposeViewController *mailController=[[MFMailComposeViewController alloc]init]; 26 //设置代理,注意这里不是delegate,而是mailComposeDelegate 27 mailController.mailComposeDelegate=self; 28 //设置收件人 29 [mailController setToRecipients:[self.toTecipients.text componentsSeparatedByString:@","]]; 30 //设置抄送人 31 if (self.ccRecipients.text.length>0) { 32 [mailController setCcRecipients:[self.ccRecipients.text componentsSeparatedByString:@","]]; 33 } 34 //设置密送人 35 if (self.bccRecipients.text.length>0) { 36 [mailController setBccRecipients:[self.bccRecipients.text componentsSeparatedByString:@","]]; 37 } 38 //设置主题 39 [mailController setSubject:self.subject.text]; 40 //设置内容 41 [mailController setMessageBody:self.body.text isHTML:YES]; 42 //添加附件 43 if (self.attachments.text.length>0) { 44 NSArray *attachments=[self.attachments.text componentsSeparatedByString:@","] ; 45 [attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 46 NSString *file=[[NSBundle mainBundle] pathForResource:obj ofType:nil]; 47 NSData *data=[NSData dataWithContentsOfFile:file]; 48 [mailController addAttachmentData:data mimeType:@"image/jpeg" fileName:obj];//第二个参数是mimeType类型,jpg图片对应image/jpeg 49 }]; 50 } 51 [self presentViewController:mailController animated:YES completion:nil]; 52 53 } 54 } 55 56 #pragma mark - MFMailComposeViewController代理方法 57 -(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{ 58 switch (result) { 59 case MFMailComposeResultSent: 60 NSLog(@"发送成功."); 61 break; 62 case MFMailComposeResultSaved://如果存储为草稿(点取消会提示是否存储为草稿,存储后可以到系统邮件应用的对应草稿箱找到) 63 NSLog(@"邮件已保存."); 64 break; 65 case MFMailComposeResultCancelled: 66 NSLog(@"取消发送."); 67 break; 68 69 default: 70 NSLog(@"发送失败."); 71 break; 72 } 73 if (error) { 74 NSLog(@"发送邮件过程中发生错误,错误信息:%@",error.localizedDescription); 75 } 76 [self dismissViewControllerAnimated:YES completion:nil]; 77 } 78 79 @end
显示效果:
2.通讯录-C
iOS中带有一个Contacts应用程序来管理联系人,但是有些时候我们希望自己的应用能够访问或者修改这些信息,这个时候就要用到AddressBook.framework框架。iOS中的通讯录是存储在数据库中的,由于iOS的权限设计,开发人员是不允许直接访问通讯录数据库的,必须依靠AddressBook提供的标准API来实现通讯录操作。通过AddressBook.framework开发者可以从底层去操作AddressBook.framework的所有信息,但是需要注意的是这个框架是基于C语言编写的,无法使用ARC来管理内存,开发者需要自己管理内存。
下面大致介绍一下通讯录操作中常用的类型:
<a> ABAddressBookRef:代表通讯录对象,通过该对象开发人员不用过多的关注通讯录的存储方式,可以直接以透明的方式去访问、保存(在使用AddressBook.framework操作联系人时,所有的增加、删除、修改后都必须执行保存操作,类似于Core Data)等。
<b> ABRecordRef:代表一个通用的记录对象,可以是一条联系人信息,也可以是一个群组,可以通过ABRecordGetRecordType()函数获得具体类型。如果作为联系人(事实上也经常使用它作为联系人),那么这个记录记录了一个完整的联系人信息(姓名、性别、电话、邮件等),每条记录都有一个唯一的ID标示这条记录(可以通过ABRecordGetRecordID()函数获得)。
<c> ABPersonRef:代表联系人信息,很少直接使用,实际开发过程中通常会使用类型为“kABPersonType”的ABRecordRef来表示联系人(由此可见ABPersonRef其实是一种类型为“kABPersonType”的ABRecordRef)
<d> ABGroupRef:代表群组,与ABPersonRef类似,很少直接使用ABGroupRef,而是使用类型为“kABGroupType”的ABRecordRef来表示群组,一个群组可以包含多个联系人,一个联系人也同样可以多个群组。
由于通讯录操作的关键是对ABRecordRef的操作,首先看一下常用的操作通讯录记录的方法:
<a> ABPersonCreate():创建一个类型为“kABPersonType”的ABRecordRef。
<b> ABRecordCopyValue():取得指定属性的值。
<c> ABRecordCopyCompositeName():取得联系人(或群组)的复合信息(对于联系人则包括:姓、名、公司等信息,对于群组则返回组名称)。
<d> ABRecordSetValue():设置ABRecordRef的属性值。注意在设置ABRecordRef的值时又分为单值属性和多值属性:单值属性设置只要通过ABRecordSetValue()方法指定属性名和值即可;多值属性则要先通过创建一个ABMutableMultiValueRef类型的变量,然后通过ABMultiValueAddValueAndLabel()方法依次添加属性值,最后通过ABRecordSetValue()方法将ABMutableMultiValueRef类型的变量设置为记录值。
<e> ABRecordRemoveValue():删除指定的属性值。
注意:由于联系人访问时(读取、设置、删除时)牵扯到大量联系人属性,可以到ABPerson.h中查询或者直接到帮助文档“Personal Information Properties”
通讯录的访问步骤一般如下:
<a> 调用ABAddressBookCreateWithOptions()方法创建通讯录对象ABAddressBookRef。
<b> 调用ABAddressBookRequestAccessWithCompletion()方法获得用户授权访问通讯录。
<c> 调用ABAddressBookCopyArrayOfAllPeople()、ABAddressBookCopyPeopleWithName()方法查询联系人信息。
<d> 读取联系人后如果要显示联系人信息则可以调用ABRecord相关方法读取相应的数据;如果要进行修改联系人信息,则可以使用对应的方法修改ABRecord信息,然后调用ABAddressBookSave()方法提交修改;如果要删除联系人,则可以调用ABAddressBookRemoveRecord()方法删除,然后调用ABAddressBookSave()提交修改操作。
<e>也就是说如果要修改或者删除都需要首先查询对应的联系人,然后修改或删除后提交更改。如果用户要增加一个联系人则不用进行查询,直接调用ABPersonCreate()方法创建一个ABRecord然后设置具体的属性,调用ABAddressBookAddRecord方法添加即可。
下面就通过一个示例演示一下如何通过ABAddressBook.framework访问通讯录,这个例子中通过一个UITableViewController模拟一下通讯录的查看、删除、添加操作。
主控制器视图,用于显示联系人,修改删除联系人:
标签:
原文地址:http://www.cnblogs.com/songshuhaoNB/p/5141241.html