iOS開發系列通訊錄、藍牙、內購、GameCenter、iCloud、Passbook系統服務開

来源:http://www.cnblogs.com/xiaoxiaojia/archive/2016/04/21/5415755.html
-Advertisement-
Play Games

--系統應用與系統服務 iOS開發過程中有時候難免會使用iOS內置的一些應用軟體和服務,例如QQ通訊錄、微信電話本會使用iOS的通訊錄,一些第三方軟體會在應用內發送簡訊等。今天將和大家一起學習如何使用系統應用、使用系統服務:http://www.jinhusns.com/Products/Downl ...


--系統應用與系統服務

iOS開發過程中有時候難免會使用iOS內置的一些應用軟體和服務,例如QQ通訊錄、微信電話本會使用iOS的通訊錄,一些第三方軟體會在應用內發送簡訊等。今天將和大家一起學習如何使用系統應用、使用系統服務:http://www.jinhusns.com/Products/Download/?type=xcj

  1. 調用系統應用

  2. 使用系統服務

    1. 簡訊與郵件

    2. 通訊錄

    3. 藍牙

    4. 社交

    5. Game Center

    6. 應用內購買

    7. iCloud

    8. Passbook

  3. 目 錄

系統應用

在開發某些應用時可能希望能夠調用iOS系統內置的電話、簡訊、郵件、瀏覽器應用,此時你可以直接使用UIApplication的OpenURL:方法指定特定的協議來打開不同的系統應用。常用的協議如下:

打電話:tel:或者tel://、telprompt:或telprompt://(撥打電話前有提示)

發簡訊:sms:或者sms://

發送郵件:mailto:或者mailto://

啟動瀏覽器:http:或者http://

下麵以一個簡單的demo演示如何調用上面幾種系統應用:

//
//  ViewController.m
//  iOSSystemApplication
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "ViewController.h"@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}#pragma mark - UI事件//打電話- (IBAction)callClicK:(UIButton *)sender {
    NSString *phoneNumber=@"18500138888";//    NSString *url=[NSString stringWithFormat:@"tel://%@",phoneNumber];//這種方式會直接撥打電話    NSString *url=[NSString stringWithFormat:@"telprompt://%@",phoneNumber];//這種方式會提示用戶確認是否撥打電話    [self openUrl:url];
}//發送簡訊- (IBAction)sendMessageClick:(UIButton *)sender {
    NSString *phoneNumber=@"18500138888";
    NSString *url=[NSString stringWithFormat:@"sms://%@",phoneNumber];
    [self openUrl:url];
}//發送郵件- (IBAction)sendEmailClick:(UIButton *)sender {
    NSString *mailAddress=@"[email protected]";
    NSString *url=[NSString stringWithFormat:@"mailto://%@",mailAddress];
    [self openUrl:url];
}//瀏覽網頁- (IBAction)browserClick:(UIButton *)sender {
    NSString *url=@"http://www.cnblogs.com/kenshincui";
    [self openUrl:url];
}#pragma mark - 私有方法
-(void)openUrl:(NSString *)urlStr{    //註意url中包含協議名稱,iOS根據協議確定調用哪個應用,例如發送郵件是“sms://”其中“//”可以省略寫成“sms:”(其他協議也是如此)    NSURL *url=[NSURL URLWithString:urlStr];
    UIApplication *application=[UIApplication sharedApplication];    if(![application canOpenURL:url]){
        NSLog(@"無法打開\"%@\",請確保此應用已經正確安裝.",url);        return;
    }
    [[UIApplication sharedApplication] openURL:url];
}

@end

不難發現當openURL:方法只要指定一個URL Schame並且已經安裝了對應的應用程式就可以打開此應用。當然,如果是自己開發的應用也可以調用openURL方法來打開。假設你現在開發了一個應用 A,如果用戶機器上已經安裝了此應用,並且在應用B中希望能夠直接打開A。那麼首先需要確保應用A已經配置了Url Types,具體方法就是在plist文件中添加URL types節點並配置URL Schemas作為具體協議,配置URL identifier作為這個URL的唯一標識,如下圖:

iOSApplication_URLTypes

然後就可以調用openURL方法像打開系統應用一樣打開第三方應用程式了:

//打開第三方應用- (IBAction)thirdPartyApplicationClick:(UIButton *)sender {
    NSString *url=@"cmj://myparams";
    [self openUrl:url];
}

就像調用系統應用一樣,協議後面可以傳遞一些參數(例如上面傳遞的myparams),這樣一來在應用中可以在AppDelegate的 -(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation代理方法中接收參數並解析。

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
    NSString *str=[NSString stringWithFormat:@"url:%@,source application:%@,params:%@",url,sourceApplication,[url host]];
    NSLog(@"%@",str);    return YES;//是否打開}

系統服務

簡訊與郵件

調用系統內置的應用來發送簡訊、郵件相當簡單,但是這麼操作也存在著一些弊端:當你點擊了發送簡訊(或郵件)操作之後直接啟動了系統的簡訊(或郵 件)應用程式,我們的應用其實此時已經處於一種掛起狀態,發送完(簡訊或郵件)之後無法自動回到應用界面。如果想要在應用程式內部完成這些操作則可以利用 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_Layout

用戶通過在此界面輸入簡訊信息點擊“發送信息”調用MFMessageComposeViewController界面來展示或進一步編輯信息,點 擊MFMessageComposeViewController中的“發送”來完成簡訊發送工作,當然用戶也可能點擊“取消”按鈕回到前一個簡訊編輯頁 面。

MFMessageComposeViewController

實現代碼:

//
//  KCSendMessageViewController.m
//  iOSSystemApplication
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "KCSendMessageViewController.h"#import <MessageUI/MessageUI.h>@interface KCSendMessageViewController ()<MFMessageComposeViewControllerDelegate>

@property (weak, nonatomic) IBOutlet UITextField *receivers;
@property (weak, nonatomic) IBOutlet UITextField *body;
@property (weak, nonatomic) IBOutlet UITextField *subject;
@property (weak, nonatomic) IBOutlet UITextField *attachments;

@end

@implementation KCSendMessageViewController#pragma mark - 控制器視圖方法
- (void)viewDidLoad {
    [super viewDidLoad];
    
}#pragma mark - UI事件
- (IBAction)sendMessageClick:(UIButton *)sender {    //如果能發送文本信息    if([MFMessageComposeViewController canSendText]){
        MFMessageComposeViewController *messageController=[[MFMessageComposeViewController alloc]init];        //收件人        messageController.recipients=[self.receivers.text componentsSeparatedByString:@","];        //信息正文        messageController.body=self.body.text;        //設置代理,註意這裡不是delegate而是messageComposeDelegate        messageController.messageComposeDelegate=self;        //如果運行商支持主題        if([MFMessageComposeViewController canSendSubject]){
            messageController.subject=self.subject.text;
        }        //如果運行商支持附件        if ([MFMessageComposeViewController canSendAttachments]) {            /*第一種方法*/
            //messageController.attachments=...;
            
            /*第二種方法*/            NSArray *attachments= [self.attachments.text componentsSeparatedByString:@","];            if (attachments.count>0) {
                [attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                    NSString *path=[[NSBundle mainBundle]pathForResource:obj ofType:nil];
                    NSURL *url=[NSURL fileURLWithPath:path];
                    [messageController addAttachmentURL:url withAlternateFilename:obj];
                }];
            }            
            /*第三種方法*/
//            NSString *path=[[NSBundle mainBundle]pathForResource:@"photo.jpg" ofType:nil];
//            NSURL *url=[NSURL fileURLWithPath:path];
//            NSData *data=[NSData dataWithContentsOfURL:url];
            /**
             *  attatchData:文件數據
             *  uti:統一類型標識,標識具體文件類型,詳情查看:幫助文檔中System-Declared Uniform Type Identifiers
             *  fileName:展現給用戶看的文件名稱
             */
//            [messageController addAttachmentData:data typeIdentifier:@"public.image"  filename:@"photo.jpg"];        }
        [self presentViewController:messageController animated:YES completion:nil];
    }
}#pragma mark - MFMessageComposeViewController代理方法//發送完成,不管成功與否-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{    switch (result) {        case MessageComposeResultSent:
            NSLog(@"發送成功.");            break;        case MessageComposeResultCancelled:
            NSLog(@"取消發送.");            break;        default:
            NSLog(@"發送失敗.");            break;
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

這裡需要強調一下:

  • MFMessageComposeViewController的代理不是通過delegate屬性指定的而是通過messageComposeDelegate指定的。

  • 可以通過幾種方式來指定發送的附件,在這個過程中請務必指定文件的尾碼,否則在發送後無法正確識別文件類別(例如如果發送的是一張jpg圖片,在發送後無法正確查看圖片)。

  • 無論發送成功與否代理方法-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result都會執行,通過代理參數中的result來獲得發送狀態。

其實只要熟悉了 MFMessageComposeViewController之後,那麼用於發送郵件的MFMailComposeViewController用法和 步驟完全一致,只是功能不同。下麵看一下MFMailComposeViewController的使用:

//
//  KCSendEmailViewController.m
//  iOSSystemApplication
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "KCSendEmailViewController.h"#import <MessageUI/MessageUI.h>@interface KCSendEmailViewController ()<MFMailComposeViewControllerDelegate>
@property (weak, nonatomic) IBOutlet UITextField *toTecipients;//收件人@property (weak, nonatomic) IBOutlet UITextField *ccRecipients;//抄送人@property (weak, nonatomic) IBOutlet UITextField *bccRecipients;//密送人@property (weak, nonatomic) IBOutlet UITextField *subject; //主題@property (weak, nonatomic) IBOutlet UITextField *body;//正文@property (weak, nonatomic) IBOutlet UITextField *attachments;//附件@end

@implementation KCSendEmailViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}#pragma mark - UI事件

- (IBAction)sendEmailClick:(UIButton *)sender {    //判斷當前是否能夠發送郵件    if ([MFMailComposeViewController canSendMail]) {
        MFMailComposeViewController *mailController=[[MFMailComposeViewController alloc]init];        //設置代理,註意這裡不是delegate,而是mailComposeDelegate        mailController.mailComposeDelegate=self;        //設置收件人        [mailController setToRecipients:[self.toTecipients.text componentsSeparatedByString:@","]];        //設置抄送人        if (self.ccRecipients.text.length>0) {
            [mailController setCcRecipients:[self.ccRecipients.text componentsSeparatedByString:@","]];
        }        //設置密送人        if (self.bccRecipients.text.length>0) {
            [mailController setBccRecipients:[self.bccRecipients.text componentsSeparatedByString:@","]];
        }        //設置主題        [mailController setSubject:self.subject.text];        //設置內容        [mailController setMessageBody:self.body.text isHTML:YES];        //添加附件        if (self.attachments.text.length>0) {
            NSArray *attachments=[self.attachments.text componentsSeparatedByString:@","] ;
            [attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                NSString *file=[[NSBundle mainBundle] pathForResource:obj ofType:nil];
                NSData *data=[NSData dataWithContentsOfFile:file];
                [mailController addAttachmentData:data mimeType:@"image/jpeg" fileName:obj];//第二個參數是mimeType類型,jpg圖片對應image/jpeg            }];
        }
        [self presentViewController:mailController animated:YES completion:nil];
        
    }
}#pragma mark - MFMailComposeViewController代理方法
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{    switch (result) {        case MFMailComposeResultSent:
            NSLog(@"發送成功.");            break;        case MFMailComposeResultSaved://如果存儲為草稿(點取消會提示是否存儲為草稿,存儲後可以到系統郵件應用的對應草稿箱找到)            NSLog(@"郵件已保存.");            break;        case MFMailComposeResultCancelled:
            NSLog(@"取消發送.");            break;            
        default:
            NSLog(@"發送失敗.");            break;
    }    if (error) {
        NSLog(@"發送郵件過程中發生錯誤,錯誤信息:%@",error.localizedDescription);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

運行效果:

MFMailComposeViewController_Layout     MFMailComposeViewController

通訊錄

 

AddressBook

iOS中帶有一個Contacts應用程式來管理聯繫人,但是有些時候我們希望自己的應用能夠訪問或者修改這些信息,這個時候就要用到 AddressBook.framework框架。iOS中的通訊錄是存儲在資料庫中的,由於iOS的許可權設計,開發人員是不允許直接訪問通訊錄資料庫 的,必須依靠AddressBook提供的標準API來實現通訊錄操作。通過AddressBook.framework開發者可以從底層去操作 AddressBook.framework的所有信息,但是需要註意的是這個框架是基於C語言編寫的,無法使用ARC來管理記憶體,開發者需要自己管理內 存。下麵大致介紹一下通訊錄操作中常用的類型:

  • ABAddressBookRef:代表通訊錄對象,通過該對象開發人員不用過多的關註通訊錄的存儲方式,可以直接以透明的方式去訪問、保存(在 使用AddressBook.framework操作聯繫人時,所有的增加、刪除、修改後都必須執行保存操作,類似於Core Data)等。

  • ABRecordRef:代表一個通用的記錄對象,可以是一條聯繫人信息,也可以是一個群組,可以通過 ABRecordGetRecordType()函數獲得具體類型。如果作為聯繫人(事實上也經常使用它作為聯繫人),那麼這個記錄記錄了一個完整的聯繫 人信息(姓名、性別、電話、郵件等),每條記錄都有一個唯一的ID標示這條記錄(可以通過ABRecordGetRecordID()函數獲得)。

  • ABPersonRef:代表聯繫人信息,很少直接使用,實際開發過程中通常會使用類型為“kABPersonType”的ABRecordRef來表示聯繫人(由此可見ABPersonRef其實是一種類型為“kABPersonType”的ABRecordRef)

  • ABGroupRef:代表群組,與ABPersonRef類似,很少直接使用ABGroupRef,而是使用類型為“kABGroupType”的ABRecordRef來表示群組,一個群組可以包含多個聯繫人,一個聯繫人也同樣可以多個群組。

由於通訊錄操作的關鍵是對ABRecordRef的操作,首先看一下常用的操作通訊錄記錄的方法:

ABPersonCreate():創建一個類型為“kABPersonType”的ABRecordRef。

ABRecordCopyValue():取得指定屬性的值。

ABRecordCopyCompositeName():取得聯繫人(或群組)的複合信息(對於聯繫人則包括:姓、名、公司等信息,對於群組則返回組名稱)。

ABRecordSetValue():設置ABRecordRef的屬性值。註意在設置ABRecordRef的值時又分為單值屬性和多值屬性: 單值屬性設置只要通過ABRecordSetValue()方法指定屬性名和值即可;多值屬性則要先通過創建一個 ABMutableMultiValueRef類型的變數,然後通過ABMultiValueAddValueAndLabel()方法依次添加屬性值, 最後通過ABRecordSetValue()方法將ABMutableMultiValueRef類型的變數設置為記錄值。

ABRecordRemoveValue():刪除指定的屬性值。

註意:

由於聯繫人訪問時(讀取、設置、刪除時)牽扯到大量聯繫人屬性,可以到ABPerson.h中查詢或者直接到幫助文檔“Personal Information Properties

通訊錄的訪問步驟一般如下:

  1. 調用ABAddressBookCreateWithOptions()方法創建通訊錄對象ABAddressBookRef。

  2. 調用ABAddressBookRequestAccessWithCompletion()方法獲得用戶授權訪問通訊錄。

  3. 調用ABAddressBookCopyArrayOfAllPeople()、ABAddressBookCopyPeopleWithName()方法查詢聯繫人信息。

  4. 讀取聯繫人後如果要顯示聯繫人信息則可以調用ABRecord相關方法讀取相應的數據;如果要進行修改聯繫人信息,則可以使用對應的方 法修改ABRecord信息,然後調用ABAddressBookSave()方法提交修改;如果要刪除聯繫人,則可以調用 ABAddressBookRemoveRecord()方法刪除,然後調用ABAddressBookSave()提交修改操作。

  5. 也就是說如果要修改或者刪除都需要首先查詢對應的聯繫人,然後修改或刪除後提交更改。如果用戶要增加一個聯繫人則不用進行查詢,直接調 用ABPersonCreate()方法創建一個ABRecord然後設置具體的屬性,調用ABAddressBookAddRecord方法添加即可。

下麵就通過一個示例演示一下如何通過ABAddressBook.framework訪問通訊錄,這個例子中通過一個UITableViewController模擬一下通訊錄的查看、刪除、添加操作。

主控制器視圖,用於顯示聯繫人,修改刪除聯繫人:

KCContactViewController.h

//
//  KCTableViewController.h
//  AddressBook
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import <UIKit/UIKit.h>/**
 *  定義一個協議作為代理
 */@protocol KCContactDelegate//新增或修改聯繫人-(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber;//取消修改或新增-(void)cancelEdit;
@end

@interface KCContactTableViewController : UITableViewController

@end

KCContactViewController.m

//
//  KCTableViewController.m
//  AddressBook
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "KCContactTableViewController.h"#import <AddressBook/AddressBook.h>#import "KCAddPersonViewController.h"@interface KCContactTableViewController ()<KCContactDelegate>

@property (assign,nonatomic) ABAddressBookRef addressBook;//通訊錄@property (strong,nonatomic) NSMutableArray *allPerson;//通訊錄所有人員@property (assign,nonatomic) int isModify;//標識是修改還是新增,通過選擇cell進行導航則認為是修改,否則視為新增@property (assign,nonatomic) UITableViewCell *selectedCell;//當前選中的單元格@end

@implementation KCContactTableViewController#pragma mark - 控制器視圖
- (void)viewDidLoad {
    [super viewDidLoad]; 
    //請求訪問通訊錄並初始化數據    [self requestAddressBook];
}//由於在整個視圖控制器周期內addressBook都駐留在記憶體中,所有當控制器視圖銷毀時銷毀該對象-(void)dealloc{    if (self.addressBook!=NULL) {
        CFRelease(self.addressBook);
    }
}#pragma mark - UI事件//點擊刪除按鈕- (IBAction)trashClick:(UIBarButtonItem *)sender {
    self.tableView.editing=!self.tableView.editing;
}#pragma mark - UITableView數據源方法

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.allPerson.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *identtityKey=@"myTableViewCellIdentityKey1";
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identtityKey];    if(cell==nil){
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey];
    }    //取得一條人員記錄    ABRecordRef recordRef=(__bridge ABRecordRef)self.allPerson[indexPath.row];    //取得記錄中得信息    NSString *firstName=(__bridge NSString *) ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);//註意這裡進行了強轉,不用自己釋放資源    NSString *lastName=(__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty);
    
    ABMultiValueRef phoneNumbersRef= ABRecordCopyValue(recordRef, kABPersonPhoneProperty);//獲取手機號,註意手機號是ABMultiValueRef類,有可能有多條
//    NSArray *phoneNumbers=(__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbersRef);//取得CFArraryRef類型的手機記錄並轉化為NSArrary    long count= ABMultiValueGetCount(phoneNumbersRef);//    for(int i=0;i<count;++i){
//        NSString *phoneLabel= (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(phoneNumbersRef, i));
//        NSString *phoneNumber=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, i));
//        NSLog(@"%@:%@",phoneLabel,phoneNumber);
//    }    
    cell.textLabel.text=[NSString stringWithFormat:@"%@ %@",firstName,lastName];    if (count>0) {
        cell.detailTextLabel.text=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));
    }    if(ABPersonHasImageData(recordRef)){//如果有照片數據        NSData *imageData= (__bridge NSData *)(ABPersonCopyImageData(recordRef));
        cell.imageView.image=[UIImage imageWithData:imageData];
    }else{
        cell.imageView.image=[UIImage imageNamed:@"avatar"];//沒有圖片使用預設頭像    }    //使用cell的tag存儲記錄id    cell.tag=ABRecordGetRecordID(recordRef);    
    return cell;
}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {    if (editingStyle == UITableViewCellEditingStyleDelete) {
        ABRecordRef recordRef=(__bridge ABRecordRef )self.allPerson[indexPath.row];
        [self removePersonWithRecord:recordRef];//從通訊錄刪除        [self.allPerson removeObjectAtIndex:indexPath.row];//從數組移除        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];//從列表刪除    } else if (editingStyle == UITableViewCellEditingStyleInsert) {        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view    }   
}#pragma mark - UITableView代理方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    self.isModify=1;
    self.selectedCell=[tableView cellForRowAtIndexPath:indexPath];
    [self performSegueWithIdentifier:@"AddPerson" sender:self];
}#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {    if([segue.identifier isEqualToString:@"AddPerson"]){
        UINavigationController *navigationController=(UINavigationController *)segue.destinationViewController;        //根據導航控制器取得添加/修改人員的控制器視圖        KCAddPersonViewController *addPersonController=(KCAddPersonViewController *)navigationController.topViewController;
        addPersonController.delegate=self;        //如果是通過選擇cell進行的導航操作說明是修改,否則為添加        if (self.isModify) {
            UITableViewCell *cell=self.selectedCell;
            addPersonController.recordID=(ABRecordID)cell.tag;//設置            NSArray *array=[cell.textLabel.text componentsSeparatedByString:@" "];            if (array.count>0) {
                addPersonController.firstNameText=[array firstObject];
            }            if (array.count>1) {
                addPersonController.lastNameText=[array lastObject];
            }
            addPersonController.workPhoneText=cell.detailTextLabel.text;
            
        }
    }
}#pragma mark - KCContact代理方法
-(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{    if (self.isModify) {
        UITableViewCell *cell=self.selectedCell;
        NSIndexPath *indexPath= [self.tableView indexPathForCell:cell];
        [self modifyPersonWithRecordID:(ABRecordID)cell.tag firstName:firstName lastName:lastName workNumber:workNumber];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
    }else{
        [self addPersonWithFirstName:firstName lastName:lastName workNumber:workNumber];//通訊簿中添加信息        [self initAllPerson];//重新初始化數據        [self.tableView reloadData];
    }
    self.isModify=0;
}
-(void)cancelEdit{
    self.isModify=0;
}#pragma mark - 私有方法/**
 *  請求訪問通訊錄
 */-(void)requestAddressBook{    //創建通訊錄對象    self.addressBook=ABAddressBookCreateWithOptions(NULL, NULL);    
    //請求訪問用戶通訊錄,註意無論成功與否block都會調用    ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {        if (!granted) {
            NSLog(@"未獲得通訊錄訪問許可權!");
        }
        [self initAllPerson];
        
    });
}/**
 *  取得所有通訊錄記錄
 */-(void)initAllPerson{    //取得通訊錄訪問授權    ABAuthorizationStatus authorization= ABAddressBookGetAuthorizationStatus();    //如果未獲得授權    if (authorization!=kABAuthorizationStatusAuthorized) {
        NSLog(@"尚未獲得通訊錄訪問授權!");        return ;
    }    //取得通訊錄中所有人員記錄    CFArrayRef allPeople= ABAddressBookCopyArrayOfAllPeople(self.addressBook);
    self.allPerson=(__bridge NSMutableArray *)allPeople;    
    //釋放資源    CFRelease(allPeople);

}/**
 *  刪除指定的記錄
 *
 *  @param recordRef 要刪除的記錄
 */-(void)removePersonWithRecord:(ABRecordRef)recordRef{
    ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//刪除    ABAddressBookSave(self.addressBook, NULL);//刪除之後提交更改}/**
 *  根據姓名刪除記錄
 */-(void)removePersonWithName:(NSString *)personName{
    CFStringRef personNameRef=(__bridge CFStringRef)(personName);
    CFArrayRef recordsRef= ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);//根據人員姓名查找    CFIndex count= CFArrayGetCount(recordsRef);//取得記錄數    for (CFIndex i=0; i<count; ++i) {
        ABRecordRef recordRef=CFArrayGetValueAtIndex(recordsRef, i);//取得指定的記錄        ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//刪除    }
    ABAddressBookSave(self.addressBook, NULL);//刪除之後提交更改    CFRelease(recordsRef);
}/**
 *  添加一條記錄
 *
 *  @param firstName  名
 *  @param lastName   姓
 *  @param iPhoneName iPhone手機號
 */-(void)addPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{    //創建一條記錄    ABRecordRef recordRef= ABPersonCreate();
    ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名    ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓    
    ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);//添加設置多值屬性    ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);//添加工作電話    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);    
    //添加記錄    ABAddressBookAddRecord(self.addressBook, recordRef, NULL);    
    //保存通訊錄,提交更改    ABAddressBookSave(self.addressBook, NULL);    //釋放資源    CFRelease(recordRef);
    CFRelease(multiValueRef);
}/**
 *  根據RecordID修改聯繫人信息
 *
 *  @param recordID   記錄唯一ID
 *  @param firstName  姓
 *  @param lastName   名
 *  @param homeNumber 工作電話
 */-(void)modifyPersonWithRecordID:(ABRecordID)recordID firstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
    ABRecordRef recordRef=ABAddressBookGetPersonWithRecordID(self.addressBook,recordID);
    ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名    ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓    
    ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);
    ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);    //保存記錄,提交更改    ABAddressBookSave(self.addressBook, NULL);    //釋放資源    CFRelease(multiValueRef);
}
@end

新增或修改控制器視圖,用於顯示一個聯繫人的信息或者新增一個聯繫人:

KCAddPersonViewController.h

//
//  KCAddPersonViewController.h
//  AddressBook
//
//  kABPersonFirstNameProperty
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import <UIKit/UIKit.h>@protocol KCContactDelegate;

@interface KCAddPersonViewController : UIViewController

@property (assign,nonatomic) int recordID;//通訊錄記錄id,如果ID不為0則代表修改否則認為是新增@property (strong,nonatomic) NSString *firstNameText;
@property (strong,nonatomic) NSString *lastNameText;
@property (strong,nonatomic) NSString *workPhoneText;

@property (strong,nonatomic) id<KCContactDelegate> delegate;

@end

KCAddPersonViewController.m

//
//  KCAddPersonViewController.m
//  AddressBook
//
//  kABPersonFirstNameProperty
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "KCAddPersonViewController.h"#import "KCContactTableViewController.h"@interface KCAddPersonViewController ()

@property (weak, nonatomic) IBOutlet UITextField *firstName;
@property (weak, nonatomic) IBOutlet UITextField *lastName;
@property (weak, nonatomic) IBOutlet UITextField *workPhone;
@end

@implementation KCAddPersonViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUI];
}#pragma mark - UI事件
- (IBAction)cancelClick:(UIBarButtonItem *)sender {
    [self.delegate cancelEdit];
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)doneClick:(UIBarButtonItem *)sender {    //調用代理方法    [self.delegate editPersonWithFirstName:self.firstName.text lastName:self.lastName.text workNumber:self.workPhone.text];
    
    [self dismissViewControllerAnimated:YES completion:nil];
}#pragma mark - 私有方法
-(void)setupUI{    if (self.recordID) {//如果ID不為0則認為是修改,此時需要初始化界面        self.firstName.text=self.firstNameText;
        self.lastName.text=self.lastNameText;
        self.workPhone.text=self.workPhoneText;
    }
}
@end

運行效果:

AddressBook

備註:

1.上文中所指的以Ref結尾的對象事實上是該對象的指針(或引用),在C語言的框架中多數類型會以Ref結尾,這個類型本身就是一個指針,定義時不需要加“*”。

2.通常方法中包含copy、create、new、retain等關鍵字的方法創建的變數使用之後需要調用對應的release方法釋放。例如:使用ABPersonCreate();創建完ABRecordRef變數後使用CFRelease()方法釋放。

3.在與很多C語言框架交互時可以都存在Obj-C和C語言類型之間的轉化(特別是Obj-C和Core Foundation框架中的一些轉化),此時可能會用到橋接,只要在強轉之後前面加上”__bridge”即可,經過橋接轉化後的類型不需要再去手動維 護記憶體,也就不需要使用對應的release方法釋放記憶體。

4.AddressBook框架中很多類型的創建、屬性設置等都是以這個類型名開發頭的方法來創建的,事實上如果大家熟悉了其他框架會發現也都是類 似的,這是Apple開發中約定俗成的命名規則(特別是C語言框架)。例如:要給ABRecordRef類型的變數設置屬性則可以通過 ABRecordSetValue()方法完成。

AddressBookUI

使用AddressBook.framework來操作通訊錄特點就是可以對通訊錄有更加精確的控制,但是缺點就是面對大量C語言API稍嫌麻煩, 於是Apple官方提供了另一套框架供開發者使用,那就是AddressBookUI.framework。例如前面查看、新增、修改人員的界面這個框架 就提供了現成的控制器視圖供開發者使用。下麵是這個框架中提供的控制器視圖:

  • ABPersonViewController:用於查看聯繫人信息(可設置編輯)。需要設置displayedPerson屬性來設置要顯示或編輯的聯繫人。

  • ABNewPersonViewController:用於新增聯繫人信息。

  • ABUnknownPersonViewController:用於顯示一個未知聯繫人(尚未保存的聯繫人)信息。需要設置displayedPerson屬性來設置要顯示的未知聯繫人。

以上三個控制器視圖均繼承於UIViewController,在使用過程中必須使用一個UINavigationController進行包裝, 否則只能看到視圖內容無法進行操作(例如對於ABNewPersonViewController如果不使用 UINavigationController進行包裝則沒有新增和取消按鈕),同時註意包裝後的控制器視圖不需要處理具體新增、修改邏輯(增加和修改的 處理邏輯對應的控制器視圖內部已經完成),但是必須處理控制器的關閉操作(調用dismissViewControllerAnimated::方法), 並且可以通過代理方法獲得新增、修改的聯繫人。下麵看一下三個控制器視圖的代理方法:

1.ABPersonViewController的displayViewDelegate代理方法:

-(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:此方法會在選擇了一個聯繫人屬性後觸發,四個參數分別代表:使用的控制器視圖、所查看的聯繫人、所選則的聯繫人屬性、該屬性是否是多值屬性。

2.ABNewPersonViewController的newPersonViewDelegate代理方法:

-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person:點擊取消或完成後觸發,如果參數中的person為NULL說明點擊了取消,否則說明點擊了完成。無論是取消還是完成操作,此方法調用時保存操作已經進行完畢,不需要在此方法中自己保存聯繫人信息。

3.ABUnkownPersonViewcontroller的unkownPersonViewDelegate代理方法:

-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person:保存此聯繫人時調用,調用後將此聯繫人返回。

-(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:選擇一個位置聯繫人屬性之後執行,返回值代表是否執行預設的選擇操作(例如如果是手機號,預設操作會撥打此電話)

除了上面三類控制器視圖在AddressBookUI中還提供了另外一個控制器視圖 ABPeoplePickerNavigationController,它與之前介紹的UIImagePickerController、 MPMediaPickerController類似,只是他是用來選擇一個聯繫人的。這個控制器視圖本身繼承於 UINavigationController,視圖自身的“組”、“取消”按鈕操作不需要開發者來完成(例如開發者不用在點擊取消是關閉當前控制器視 圖,它自身已經實現了關閉方法),當然這裡主要說一下這個控制器視圖的peoplePickerDelegate代理方法:

-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person: 選擇一個聯繫人後執行。此代理方法實現後代理方法“-(void)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier”不會再執行。並且一旦實現了這個代理方法用戶只能選擇到 聯繫人視圖,無法查看具體聯繫人的信息。

-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker:用戶點擊取消後執行。

-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:選擇聯繫人具體的屬性後執行,註意如 果要執行此方法則不能實現-(void)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person代理方法,此時如果點擊一個具體聯繫人會導航到聯繫人詳細信息界面,用戶點擊具 體的屬性後觸發此方法。

下麵就看一下上面四個控制器視圖的使用方法,在下麵的程式中定義了四個按鈕,點擊不同的按鈕調用不同的控制器視圖用於演示:

//
//  ViewController.m
//  AddressBookUI
//
//  Created by Kenshin Cui on 14/04/05.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//#import "ViewController.h"#import <AddressBookUI/AddressBookUI.h>@interface ViewController ()<ABNewPersonViewControllerDelegate,ABUnknownPersonViewControllerDelegate,ABPeoplePickerNavigationControllerDelegate,ABPersonViewControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}#pragma mark - UI事件//添加聯繫人- (IBAction)addPersonClick:(UIButton *)sender {
    ABNewPersonViewController *newPersonController=[[ABNewPersonViewController alloc]init];    //設置代理    newPersonController.newPersonViewDelegate=self;    //註意ABNewPersonViewController必須包裝一層UINavigationController才能使用,否則不會出現取消和完成按鈕,無法進行保存等操作    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:newPersonController];
    [self presentViewController:navigationController animated:YES completion:nil];
}//- (IBAction)unknownPersonClick:(UIButton *)sender {
    ABUnknownPersonViewController *unknownPersonController=[[ABUnknownPersonViewController alloc]init];    //設置未知人員    ABRecordRef recordRef=ABPersonCreate();
    ABRecordSetValue(recordRef, kABPersonFirstNameProperty, @"Kenshin", NULL);
    ABRecordSetValue(recordRef, kABPersonLastNameProperty, @"Cui", NULL);
    ABMultiValueRef multiValueRef=ABMultiValueCreateMutable(kABStringPropertyType);
    ABMultiValueAddValueAndLabel(multiValueRef, @"18500138888", kABHomeLabel, NULL);
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
    unknownPersonController.displayedPerson=recordRef;    //設置代理    unknownPersonController.unknownPersonViewDelegate=self;    //設置其他屬性    unknownPersonController.allowsActions=YES;//顯示標準操作按鈕    unknownPersonController.allowsAddingToAddressBook=YES;//是否允許將聯繫人添加到地址簿    
    CFRelease(multiValueRef);
    CFRelease(recordRef);    //使用導航控制器包裝    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:unknownPersonController];
    [self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)showPersonClick:(UIButton *)sender {
    ABPersonViewController *personController=[[ABPersonViewController alloc]init];    //設置聯繫人    ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, NULL);
    ABRecordRef recordRef= ABAddressBookGetPersonWithRecordID(addressBook, 1);//取得id為1的聯繫人記錄    personController.displayedPerson=recordRef;    //設置代理    personController.personViewDelegate=self;    //設置其他屬性    personController.allowsActions=YES;//是否顯示發送信息、共用聯繫人等按鈕    personController.allowsEditing=YES;//允許編輯
//    personController.displayedProperties=@[@(kABPersonFirstNameProperty),@(kABPersonLastNameProperty)];//顯示的聯繫人屬性信息,預設顯示所有信息
    
    //使用導航控制器包裝    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:personController];
    [self presentViewController:navigationController animated:YES completion:nil];
}

- (IBAction)selectPersonClick:(UIButton *)sender {
    ABPeoplePickerNavigationController *peoplePickerController=[[ABPeoplePickerNavigationController alloc]init];    //設置代理    peoplePickerController.peoplePickerDelegate=self;
    [self presentViewController:peoplePickerController animated:YES completion:nil];
}#pragma mark - ABNewPersonViewController代理方法//完成新增(點擊取消和完成按鈕時調用),註意這裡不用做實際的通訊錄增加工作,此代理方法調用時已經完成新增,當保存成功的時候參數中得person會返回保存的記錄,如果點擊取消person為NULL-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person{    //如果有聯繫人信息    if (person) {
        NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
    }else{
        NSLog(@"點擊了取消.");
    }    //關閉模態視圖視窗    [self dismissViewControllerAnimated:YES completion:nil];
    
}#pragma mark - ABUnknownPersonViewController代理方法//保存未知聯繫人時觸發-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person{    if (person) {
        NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeN

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近迷戀上了釣魚,可是總釣不到大魚,所以就畫條大魚來安慰一下我這柔弱的心靈。 先上圖: 上面這個就是今晚上我要跟大家分享的小DEMO,我給他起名字就“大魚吃小魚之孤單的大魚”。 轉入正題,這條大魚分為三部分:頭,尾巴,眼睛。首先看一下這條魚的框架,如下麵所示,class已經說得很直接了 首先給整條魚 ...
  • 介紹 Emmet (前身為 Zen Coding) 是一個能大幅度提高前端開發效率的一個工具。 基本上,大多數的文本編輯器都會允許你存儲和重用一些代碼塊,我們稱之為“片段”。雖然片段能很好地推動你得生產力,但大多數的實現都有這樣一個缺點:你必須先定義你得代碼片段,並且不能再運行時進行拓展。 Emme ...
  • AngularJS Select(選項框) AngularJS 可是使用數組或對象創建一個下拉列表選項。使用ng-options創建選項框 在AngularJS 中我們可以使用ng-option指令來創建一個下拉列表,列表通過對象和數組迴圈輸出 實例: <div ng-app="myApp" ng- ...
  • 前言 通過百度搜索歌曲,進入到酷我聽歌頁面時,發現沒有歌詞定位功能。 突然想到自己可不可以實現這個效果,於是就有了這篇文章。 分析 放上我喜歡的一首歌《Hello》 。界面如下 通過分析html源碼,得到以下結果 1、最重要的兩部分區域: 歌詞區域 、 播放進度區域 2、歌詞區域是一個 div [c ...
  • 移動設備優先: 為了讓開發的網站對移動設備友好,確保適當的繪製和觸屏縮放,需要在網頁的head之中添加viewport meat標簽:如下: <metaname="viewport"content="width=device-width, initial-scale=1.0"> 響應式圖像: 通過對 ...
  • 今天商城系統的後臺要添加一個Tab切換的效果,一開始沒有思路想要自己去實踐這個效果 從網上找jquery 已經有了很好看的案例,實現之後我來學習下思路是如何完成的 ...
  • 頁面必須設置為html5文檔類型 <!DOCTYPE html> <html lang="zh-CN"> ... </html> 適應移動設備 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scal ...
  • 在Android常用編程中,Handler在進行非同步操作並處理返回結果時經常被使用。其實這可能導致記憶體泄露,代碼中哪裡可能導致記憶體泄露,又是如何導致記憶體泄露的呢?那我們就慢慢分析一下。http://www.jinhusns.com/Products/Download/?type=xcj 在Andro ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...