iOS 短信與電話事件的獲取

 

整理:iOS 短信與電話事件的獲取

 

background information:php

 

Core Telephony

iOS 4.0 的官方 API 裡頭,多了一個叫作 Core Telephony 的 framework;一直以來 Core Telephony 都是 private API,現在開放出來,可是從文件來看,裡頭根本沒有幾行,既沒有告訴你應該怎麼用,也沒有範例,你從 framework 裡頭寥寥四個 class 的 header 中,也搞不清楚,究竟能夠把這個東西用在什麼用途上。html

目前只知道能夠拿來作兩件事情:1. 知道目前你這隻 iPhone 用的是哪個電信商的服務;2. 知道現在 iPhone 是否是在打電話。數據庫

 

※ 電信商資訊

用 CTTelephonyNetworkInfo 與 CTCarrier 這兩個 class,就能夠取得電信商資訊,例如:api

CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *carrier = info.subscriberCellularProvider;
NSLog(@"carrier:%@", [carrier description]);

倒出來的結果像是:網絡

CTCarrier (0x140dc0) {
	Carrier name: [中華電信]
	Mobile Country Code: [466]
	Mobile Network Code:[92]
	ISO Country Code:[tw]
	Allows VOIP? [YES]
}

然後,若是你對 CTTelephonyNetworkInfo 餵一個 block 進去,像是:app

info.subscriberCellularProviderDidUpdateNotifier = ^(CTCarrier *carrier) {NSLog(@"carrier:%@", [carrier description]);};

如此一來,當你的 iPhone 漫遊到了其餘網路的時候,就會執行你這段 block,但光是知道手機現在漫遊在哪個電信商的網路裡頭,大概能作的,就是一些跟電信商關係密切的服務之類,你或許能夠決定軟體裡頭有哪些功能,必定 要在某個電信商的網路才能用;電信商本身作 iPhone 軟體的時候大概會想作這種事情。框架

※ 通話資料

用 CTCallCenter 與 CTCall 這兩個 class,即可以知道目前 iPhone 是否在通話中。CTCallCenter 的用途是用來監控是否是有電話打進來、正在接聽、或是已經掛斷,而 CTCall 則是將每一則通話事件包裝成一個物件。我們先寫一小段程式-less

CTCallCenter *center = [[CTCallCenter alloc] init];
center.callEventHandler = ^(CTCall *call) {
	NSLog(@"call:%@", [call description]);
};

然後,在實機上執行,接著打通電話到這支 iPhone 上,打通電話進去,然後馬上掛斷(人好端端的,幹嘛為了測試程式跟本身的電話費帳單過不去呢?)就能夠看到 iPhone 執行了我們的 block,把 CTCall 物件倒出來:iphone

CTCall (0x143400) {
	callState: [CTCallStateIncoming]
	Call ID: [CE5F9337-1990-4254-8797-1CCEA85B061B]
}
CTCall (0x10bac0) {
	callState: [CTCallStateDisconnected]
	Call ID: [CE5F9337-1990-4254-8797-1CCEA85B061B]
}

CTCall 物件只有兩個屬性,一是通話狀態(來電中、通話中…),二是這則通話的 unique id,除此以外沒有其餘資訊,你沒辦法知道這通電話是從哪裡打來的,只能知道有電話進來而已,也沒辦法透過這個 API 打電話出去。ide

大抵上能夠想到的用途,就是當你的程式執行到一半的時候,程式流程被電話打斷,這時候就可能要中斷本來正在作的事情,在通話結束之後恢復。

最後,CTCallCenter 與 CTTelephonyNetworkInfo,在模擬器上是沒有辦法用的,呼叫 alloc、init 之後回傳的結果只會是 nil。

Be Sociable, Share!

1.首先添加coreTelephony.framework

  1. #import <UIKit/UIKit.h>  

  2. #include <notify.h>  

  3. #include <stdio.h>  

  4. #include <stdarg.h>  

  5. #include <string.h>  

  6. typedef struct __CTSMSMessage CTSMSMessage;  

  7. NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *);  

  8. NSString *CTSMSMessageCopyText(void *, CTSMSMessage *);  

  9. id CTTelephonyCenterGetDefault(void);  

  10. void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);  

  11. void dolog(id formatstring,...)  

  12. {  

  13.     va_list arglist;  

  14.     if (formatstring)  

  15.     {  

  16.         va_start(arglist, formatstring);  

  17.         id outstring = [[NSString alloc] initWithFormat:formatstring arguments:arglist];  

  18.         printf("%s\n", [outstring UTF8String]);  

  19.         va_end(arglist);  

  20.     }  

  21. }  

  22. static void callback(CFNotificationCenterRef center,  

  23.                      void *observer, CFStringRef name,  

  24.                      const void *object, CFDictionaryRef userInfo)  

  25. {  

  26.       

  27.     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  

  28.     // printf("NOTIFICATION: %s\n", [name UTF8String]);  

  29.     if (!userInfo) return;  

  30.       

  31.     NSDictionary *info = (NSDictionary*)userInfo;  

  32.     int dcount = CFDictionaryGetCount(userInfo);  

  33.     id keys = [(NSDictionary*)userInfo allKeys];  

  34.     int i;  

  35.     for (i = 0; i < dcount; i++)  

  36.     {  

  37.         id key = [keys objectAtIndex:i];  

  38.         dolog(@"  %@: %@", key, [info objectForKey:key]);  

  39.     }      

  40.       

  41.       

  42.     if ([[(NSDictionary *)userInfo allKeys]  

  43.          containsObject:@"kCTSMSMessage"]) // SMS Message  

  44.     {  

  45.         CTSMSMessage *message = (CTSMSMessage *)  

  46.         [(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];  

  47.         NSString *address = CTSMSMessageCopyAddress(NULL, message);  

  48.         NSString *text = CTSMSMessageCopyText(NULL, message);  

  49.         NSArray *lines = [text componentsSeparatedByString:@"\n"];  

  50.           

  51.         printf("  %s %d\n", [address cString], [lines count]);  

  52.         printf("  %s\n", [text cString]);  

  53.         fflush(stdout);  

  54.     }  

  55.       

  56.     [pool release];  

  57.       

  58.     return ;  

  59. }  

  60. static void signalHandler(int sigraised)  

  61. {  

  62.     printf("\nInterrupted.\n");  

  63.     exit(0);  

  64. }  

  65. int main(int argc, char **argv)  

  66. {  

  67.     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  

  68.       

  69.     // Initialize listener by adding CT Center observer implicit  

  70.     id ct = CTTelephonyCenterGetDefault();  

  71.     CTTelephonyCenterAddObserver( ct, NULL, callback,NULL,NULL,  

  72.                                  CFNotificationSuspensionBehaviorHold);  

  73.       

  74.     // Handle Interrupts  

  75.     sig_t oldHandler = signal(SIGINT, signalHandler);  

  76.     if (oldHandler == SIG_ERR)  

  77.     {  

  78.         printf("Could not establish new signal handler");  

  79.         exit(1);  

  80.     }  

  81.       

  82.     // Run loop lets me catch notifications  

  83.     printf("Starting run loop and watching for notification.\n");  

  84.     CFRunLoopRun();  

  85.       

  86.     // Shouldn't ever get here. Bzzzt  

  87.     printf("Unexpectedly back from CFRunLoopRun()!\n");  

  88.     [pool release];  

  89. }  

2.

 

  1. extern NSString* const kCTSMSMessageReceivedNotification;  

  2. extern NSString* const kCTSMSMessageReplaceReceivedNotification;  

  3. extern NSString* const kCTSIMSupportSIMStatusNotInserted;  

  4. extern NSString* const kCTSIMSupportSIMStatusReady;   

  5.   

  6.   

  7.   

  8. typedef struct __CTCall CTCall;  

  9. extern NSString *CTCallCopyAddress(void*, CTCall *);  

  10.   

  11. void* CTSMSMessageSend(id server,id msg);  

  12. typedef struct __CTSMSMessage CTSMSMessage;    

  13. NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *);    

  14. NSString *CTSMSMessageCopyText(void *, CTSMSMessage *);  

  15.   

  16.   

  17. int CTSMSMessageGetRecordIdentifier(void * msg);  

  18. NSString * CTSIMSupportGetSIMStatus();    

  19. NSString * CTSIMSupportCopyMobileSubscriberIdentity();   

  20.   

  21. id  CTSMSMessageCreate(void* unknow/*always 0*/,NSString* number,NSString* text);  

  22. void * CTSMSMessageCreateReply(void* unknow/*always 0*/,void * forwardTo,NSString* text);  

  23.   

  24.   

  25. id CTTelephonyCenterGetDefault(void);  

  26. void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);  

  27. void CTTelephonyCenterRemoveObserver(id,id,NSString*,void*);  

  28. int CTSMSMessageGetUnreadCount(void);   

  29.   

  30. static void callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)   

  31. {  

  32.     NSString *notifyname=(NSString *)name;  

  33.     if ([notifyname isEqualToString:@"kCTCallStatusChangeNotification"])//電話  

  34.     {  

  35.         NSDictionary *info = (NSDictionary*)userInfo;  

  36.           

  37.         NSString *state=[[info objectForKey:@"kCTCallStatus"] stringValue];  

  38.         if ([state isEqualToString:@"5"])//disconnect  

  39.             NSLog(@"未接:%@",state);  

  40.           

  41.     }  

  42.     else if ([notifyname isEqualToString:@"kCTCallIdentificationChangeNotification"])  

  43.     {  

  44. //        CTCallCenter *center = [[CTCallCenter alloc] init];  

  45. //        center.callEventHandler = ^(CTCall *call) {  

  46. //            NSLog(@"call:%@", [call description]);  

  47. //        };  

  48.           

  49.         NSDictionary *info = (NSDictionary *)userInfo;  

  50.         CTCall *call = (CTCall *)[info objectForKey:@"kCTCall"];  

  51.         NSString *caller = CTCallCopyAddress(NULL, call);  

  52.         NSLog(@"電話號碼:%@",caller);  

  53.         //CTCallDisconnect(call);  

  54.         /* or one of the following functions: CTCallAnswer 

  55.          CTCallAnswerEndingActive 

  56.          CTCallAnswerEndingAllOthers 

  57.          CTCallAnswerEndingHeld 

  58.         */  

  59.           

  60.     }  

  61.     else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])  

  62.     {  

  63.           

  64.     }  

  65.     else if ([notifyname isEqualToString:@"kCTSMSMessageReceivedNotification"])  

  66.     {//api 已過時  

  67.         if ([[(NSDictionary *)userInfo allKeys]    

  68.              containsObject:@"kCTSMSMessage"]) // SMS Message    

  69.         {    

  70.             CTSMSMessage *message = (CTSMSMessage *)    

  71.             [(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];    

  72.             NSString *address = CTSMSMessageCopyAddress(NULL, message);    

  73.             NSString *text = CTSMSMessageCopyText(NULL, message);    

  74.             //NSArray *lines = [text componentsSeparatedByString:@"\n"];    

  75.               

  76.             //printf("  %s %d\n", [address cString], [lines count]);    

  77.             //printf("  %s\n", [text cString]);    

  78.             fflush(stdout);    

  79.           

  80.         }  

  81.     }  

  82.     else if ([notifyname isEqualToString:@"kCTMessageReceivedNotification"])//收到短信  

  83.     {  

  84.         /* 

  85.          kCTMessageIdKey = "-2147483636"; 

  86.          kCTMessageTypeKey = 1;  

  87.         */  

  88.           

  89.         NSDictionary *info = (NSDictionary *)userInfo;  

  90.         CFNumberRef msgID = (CFNumberRef)[info objectForKey:@"kCTMessageIdKey"];  

  91.         int result;  

  92.         CFNumberGetValue((CFNumberRef)msgID, kCFNumberSInt32Type, &result);  

  93.           

  94.         /* 

  95.         Class CTMessageCenter = NSClassFromString(@"CTMessageCenter"); 

  96.         id mc = [CTMessageCenter sharedMessageCenter]; 

  97.         id incMsg = [mc incomingMessageWithId: result]; 

  98.          

  99.         int msgType = (int)[incMsg messageType]; 

  100.          

  101.         if (msgType == 1) //experimentally detected number 

  102.         { 

  103.             id phonenumber = [incMsg sender]; 

  104.              

  105.             NSString *senderNumber = (NSString *)[phonenumber canonicalFormat]; 

  106.             id incMsgPart = [[incMsg items] objectAtIndex:0]; 

  107.             NSData *smsData = [incMsgPart data]; 

  108.             NSString *smsText = [[NSString alloc] initWithData:smsData encoding:NSUTF8StringEncoding]; 

  109.         } 

  110.         */  

  111.     }  

  112.     else if ([notifyname isEqualToString:@"kCTIndicatorsSignalStrengthNotification"])//信號  

  113.     {  

  114.         /* 

  115.         kCTIndicatorsGradedSignalStrength = 2; 

  116.         kCTIndicatorsRawSignalStrength = "-101"; 

  117.         kCTIndicatorsSignalStrength = 19; 

  118.         */  

  119.           

  120.     }  

  121.     else if ([notifyname isEqualToString:@"kCTRegistrationStatusChangedNotification"])//網絡註冊狀態  

  122.     {  

  123.         /* 

  124.          kCTRegistrationInHomeCountry = 1; 

  125.          kCTRegistrationStatus = kCTRegistrationStatusRegisteredHome; 

  126.         */  

  127.           

  128.     }  

  129.     else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])  

  130.     {  

  131.         /* 

  132.          kCTRegistrationDataActive = 1; 

  133.          kCTRegistrationDataAttached = 1; 

  134.          kCTRegistrationDataConnectionServices =     ( 

  135.          kCTDataConnectionServiceTypeInternet, 

  136.          kCTDataConnectionServiceTypeWirelessModemTraffic, 

  137.          kCTDataConnectionServiceTypeWirelessModemAuthentication 

  138.          ); 

  139.          kCTRegistrationDataContextID = 0; 

  140.          kCTRegistrationDataIndicator = kCTRegistrationDataIndicator3G; 

  141.          kCTRegistrationDataStatus = kCTRegistrationDataStatusAttachedAndActive; 

  142.          kCTRegistrationDataStatusInternationalRoaming = 1; 

  143.          kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN; 

  144.         */   

  145.     }  

  146.     else if ([notifyname isEqualToString:@"kCTRegistrationCellChangedNotification"])  

  147.     {  

  148.         /* 

  149.          kCTRegistrationGsmCellId = 93204174; 

  150.          kCTRegistrationGsmLac = 55583; 

  151.          kCTRegistrationInHomeCountry = 1; 

  152.          kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN;  

  153.         */  

  154.     }  

  155.     else if ([notifyname isEqualToString:@"kCTIndicatorRadioTransmitNotification"])  

  156.     {  

  157.         /* 

  158.         kCTRadioTransmitDCHStatus = 1; 

  159.         */   

  160.     }  

  161.     //int unread=CTSMSMessageGetUnreadCount();  

  162.     //if (unread>0)  

  163.         //NSLog(@"未讀短信:%d",unread);  

  164.           

  165.     NSLog(@"名字:%@-詳細:%@",notifyname,userInfo);  

  166.       

  167.        

  168. }  

  169.   

  170. static void signalHandler(int sigraised)    

  171. {    

  172.     printf("\nInterrupted.\n");    

  173.     exit(0);    

  174. }   

  175. <span style="font-family:Arial, Verdana, sans-serif;"><span style="white-space: normal;">  

  176. </span></span>  

 

執行

  1. id ct = CTTelephonyCenterGetDefault();  

  2.     CTTelephonyCenterAddObserver(ct, NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);  

  3.     // Handle Interrupts    

  4.     sig_t oldHandler = signal(SIGINT, signalHandler);    

  5.     if (oldHandler == SIG_ERR)    

  6.     {    

  7.         printf("Could not establish new signal handler");    

  8.         exit(1);    

  9.     }   

  10.     // Run loop lets me catch notifications    

  11.     printf("Starting run loop and watching for notification.\n");    

  12.     //CFRunLoopRun();   

 

3.

/********private api********/

無庸置疑,如下的全部操做必須創建在已越獄的iPhone手機上。

首先,在創建工程以後咱們要引入一個名爲CoreTelephony.framework的框架,他是一個是一個有關電話、短信和郵件通信的框架。

注: 使用4.x的SDK的開發者能夠清楚的看到這個框架中有關電話和運營商的各類類(/Developer/Platforms /iPhoneOS.platform/Developer/SDKs/iPhoneOS4.x.sdk/System/Library /Frameworks/CoreTelephony.framework),而其在3.x的SDK中是一個私有框架(/Developer /Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.x.sdk/System /Library/PrivateFrameworks/CoreTelephony.framework),咱們可使用class-dump(目前最 新版本爲3.3.4)去dump去獲得那些有關的類。

接着,咱們要引入一些沒有在文檔中出現,但又確實存在的函數,因爲咱們的實現文件爲.mm文件因此引入時最好使用extern "C"方式:

extern "C" CFNotificationCenterRef CTTelephonyCenterGetDefault(void); // 得到 TelephonyCenter (電話消息中心) 的引用
extern "C" void CTTelephonyCenterAddObserver(CFNotificationCenterRef center, const void *observer, CFNotificationCallback callBack, CFStringRef name, const void *object, CFNotificationSuspensionBehavior suspensionBehavior);
extern "C" void CTTelephonyCenterRemoveObserver(CFNotificationCenterRef center, const void *observer, CFStringRef name, const void *object);
extern "C" NSString *CTCallCopyAddress(void *, CTCall *call); //得到來電號碼
extern "C" void CTCallDisconnect(CTCall *call); // 掛斷電話
extern "C" void CTCallAnswer(CTCall *call); // 接電話
extern "C" void CTCallAddressBlocked(CTCall *call);
extern "C" int CTCallGetStatus(CTCall *call); // 得到電話狀態 撥出電話時爲3,有呼入電話時爲4,掛斷電話時爲5
extern "C" int CTCallGetGetRowIDOfLastInsert(void); // 得到最近一條電話記錄在電話記錄數據庫中的位置

以上這些方法都在CoreTelephony這個庫中實現,這也是爲何咱們要一開始就引入這個框架了。

第三步:咱們就要是要在SpringBaord啓動以後就將咱們的回調函數註冊到CTTelephonyCenter這個消息中心,註冊咱們就放在Hook到SpringBoard的applicationDidFinishLaunching:的那個函數中去:

CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, &callBack, CFSTR("kCTCallStatusChangeNotification"), NULL, CFNotificationSuspensionBehaviorHold);
  
這裏用到的CTTelephonyCenterAddObsever這個函數基本上與文檔中給出的CFNotificationCenterAddObserver這個函數同樣,因此咱們能夠參照後者對前者進行使用(經我測試用法基本相同)。

最後,就是對回調函數的實現:

static void callBack(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {

  if ([(NSString *)name isEqualToString:@"kCTCallStatusChangeNotification"]) {

    CTCall *call = (CTCall *)[(NSDictionary *)userInfo objectForKey:@"kCTCall"];

    NSString *caller = CTCallCopyAddress(NULL, call); // caller 即是來電號碼

    CTCallDisconnect(call); // 掛斷電話

    CTCallAnswer(call); // 接電話

    CTCallGetStatus(CTCall *call); // 得到電話狀態 撥出電話時爲3,有呼入電話時爲4,掛斷電話時爲5

    CTCallGetGetRowIDOfLastInsert(void); // 得到最近一條電話記錄在電話記錄數據庫(call_history.db)中的位置(ROWID)

  }

}

以上代碼經測試可使用:

測試機型:iPhone 3GS

系統版本:iOS 4.3.3

手機狀態:已越獄

測試結果:Perfect!

http://www.cnblogs.com/OtionSky/archive/2011/11/10/iPhone_TelephoneCenter.html

 

 

 

1.私有api獲取電話號碼

須要CoreTelephony.framework

 

  1. extern NSString* CTSettingCopyMyPhoneNumber();  

  2.   

  3.   

  4. +(NSString *) phoneNumber {  

  5.     NSString *phone = CTSettingCopyMyPhoneNumber();  

  6.   

  7.     return phone;  

  8. }

相關文章
相關標籤/搜索