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


 

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

 
background information:

 

Core Telephony

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

目前只知道可以拿來做兩件事情:1. 知道目前你這隻 iPhone 用的是哪個電信商的服務;2. 知道現在 iPhone 是不是在打電話。

 

※ 電信商資訊

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

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 進去,像是:

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

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

※ 通話資料

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

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

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

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 打電話出去。

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

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

Be Sociable, Share!

 

1.

 

首先添加coreTelephony.framework

 

[cpp]  view plain copy
 
  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.

 

[cpp]  view plain copy
 
  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>  

 

執行

[cpp]  view plain copy
 
  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;  
 轉: http://blog.csdn.net/slinloss/article/details/8722806


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM