background information:php
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
#import <UIKit/UIKit.h>
#include <notify.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
typedef struct __CTSMSMessage CTSMSMessage;
NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *);
NSString *CTSMSMessageCopyText(void *, CTSMSMessage *);
id CTTelephonyCenterGetDefault(void);
void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);
void dolog(id formatstring,...)
{
va_list arglist;
if (formatstring)
{
va_start(arglist, formatstring);
id outstring = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
printf("%s\n", [outstring UTF8String]);
va_end(arglist);
}
}
static void callback(CFNotificationCenterRef center,
void *observer, CFStringRef name,
const void *object, CFDictionaryRef userInfo)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// printf("NOTIFICATION: %s\n", [name UTF8String]);
if (!userInfo) return;
NSDictionary *info = (NSDictionary*)userInfo;
int dcount = CFDictionaryGetCount(userInfo);
id keys = [(NSDictionary*)userInfo allKeys];
int i;
for (i = 0; i < dcount; i++)
{
id key = [keys objectAtIndex:i];
dolog(@" %@: %@", key, [info objectForKey:key]);
}
if ([[(NSDictionary *)userInfo allKeys]
containsObject:@"kCTSMSMessage"]) // SMS Message
{
CTSMSMessage *message = (CTSMSMessage *)
[(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];
NSString *address = CTSMSMessageCopyAddress(NULL, message);
NSString *text = CTSMSMessageCopyText(NULL, message);
NSArray *lines = [text componentsSeparatedByString:@"\n"];
printf(" %s %d\n", [address cString], [lines count]);
printf(" %s\n", [text cString]);
fflush(stdout);
}
[pool release];
return ;
}
static void signalHandler(int sigraised)
{
printf("\nInterrupted.\n");
exit(0);
}
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Initialize listener by adding CT Center observer implicit
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver( ct, NULL, callback,NULL,NULL,
CFNotificationSuspensionBehaviorHold);
// Handle Interrupts
sig_t oldHandler = signal(SIGINT, signalHandler);
if (oldHandler == SIG_ERR)
{
printf("Could not establish new signal handler");
exit(1);
}
// Run loop lets me catch notifications
printf("Starting run loop and watching for notification.\n");
CFRunLoopRun();
// Shouldn't ever get here. Bzzzt
printf("Unexpectedly back from CFRunLoopRun()!\n");
[pool release];
}
2.
extern NSString* const kCTSMSMessageReceivedNotification;
extern NSString* const kCTSMSMessageReplaceReceivedNotification;
extern NSString* const kCTSIMSupportSIMStatusNotInserted;
extern NSString* const kCTSIMSupportSIMStatusReady;
typedef struct __CTCall CTCall;
extern NSString *CTCallCopyAddress(void*, CTCall *);
void* CTSMSMessageSend(id server,id msg);
typedef struct __CTSMSMessage CTSMSMessage;
NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *);
NSString *CTSMSMessageCopyText(void *, CTSMSMessage *);
int CTSMSMessageGetRecordIdentifier(void * msg);
NSString * CTSIMSupportGetSIMStatus();
NSString * CTSIMSupportCopyMobileSubscriberIdentity();
id CTSMSMessageCreate(void* unknow/*always 0*/,NSString* number,NSString* text);
void * CTSMSMessageCreateReply(void* unknow/*always 0*/,void * forwardTo,NSString* text);
id CTTelephonyCenterGetDefault(void);
void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);
void CTTelephonyCenterRemoveObserver(id,id,NSString*,void*);
int CTSMSMessageGetUnreadCount(void);
static void callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
NSString *notifyname=(NSString *)name;
if ([notifyname isEqualToString:@"kCTCallStatusChangeNotification"])//電話
{
NSDictionary *info = (NSDictionary*)userInfo;
NSString *state=[[info objectForKey:@"kCTCallStatus"] stringValue];
if ([state isEqualToString:@"5"])//disconnect
NSLog(@"未接:%@",state);
}
else if ([notifyname isEqualToString:@"kCTCallIdentificationChangeNotification"])
{
// CTCallCenter *center = [[CTCallCenter alloc] init];
// center.callEventHandler = ^(CTCall *call) {
// NSLog(@"call:%@", [call description]);
// };
NSDictionary *info = (NSDictionary *)userInfo;
CTCall *call = (CTCall *)[info objectForKey:@"kCTCall"];
NSString *caller = CTCallCopyAddress(NULL, call);
NSLog(@"電話號碼:%@",caller);
//CTCallDisconnect(call);
/* or one of the following functions: CTCallAnswer
CTCallAnswerEndingActive
CTCallAnswerEndingAllOthers
CTCallAnswerEndingHeld
*/
}
else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])
{
}
else if ([notifyname isEqualToString:@"kCTSMSMessageReceivedNotification"])
{//api 已過時
if ([[(NSDictionary *)userInfo allKeys]
containsObject:@"kCTSMSMessage"]) // SMS Message
{
CTSMSMessage *message = (CTSMSMessage *)
[(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];
NSString *address = CTSMSMessageCopyAddress(NULL, message);
NSString *text = CTSMSMessageCopyText(NULL, message);
//NSArray *lines = [text componentsSeparatedByString:@"\n"];
//printf(" %s %d\n", [address cString], [lines count]);
//printf(" %s\n", [text cString]);
fflush(stdout);
}
}
else if ([notifyname isEqualToString:@"kCTMessageReceivedNotification"])//收到短信
{
/*
kCTMessageIdKey = "-2147483636";
kCTMessageTypeKey = 1;
*/
NSDictionary *info = (NSDictionary *)userInfo;
CFNumberRef msgID = (CFNumberRef)[info objectForKey:@"kCTMessageIdKey"];
int result;
CFNumberGetValue((CFNumberRef)msgID, kCFNumberSInt32Type, &result);
/*
Class CTMessageCenter = NSClassFromString(@"CTMessageCenter");
id mc = [CTMessageCenter sharedMessageCenter];
id incMsg = [mc incomingMessageWithId: result];
int msgType = (int)[incMsg messageType];
if (msgType == 1) //experimentally detected number
{
id phonenumber = [incMsg sender];
NSString *senderNumber = (NSString *)[phonenumber canonicalFormat];
id incMsgPart = [[incMsg items] objectAtIndex:0];
NSData *smsData = [incMsgPart data];
NSString *smsText = [[NSString alloc] initWithData:smsData encoding:NSUTF8StringEncoding];
}
*/
}
else if ([notifyname isEqualToString:@"kCTIndicatorsSignalStrengthNotification"])//信號
{
/*
kCTIndicatorsGradedSignalStrength = 2;
kCTIndicatorsRawSignalStrength = "-101";
kCTIndicatorsSignalStrength = 19;
*/
}
else if ([notifyname isEqualToString:@"kCTRegistrationStatusChangedNotification"])//網絡註冊狀態
{
/*
kCTRegistrationInHomeCountry = 1;
kCTRegistrationStatus = kCTRegistrationStatusRegisteredHome;
*/
}
else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])
{
/*
kCTRegistrationDataActive = 1;
kCTRegistrationDataAttached = 1;
kCTRegistrationDataConnectionServices = (
kCTDataConnectionServiceTypeInternet,
kCTDataConnectionServiceTypeWirelessModemTraffic,
kCTDataConnectionServiceTypeWirelessModemAuthentication
);
kCTRegistrationDataContextID = 0;
kCTRegistrationDataIndicator = kCTRegistrationDataIndicator3G;
kCTRegistrationDataStatus = kCTRegistrationDataStatusAttachedAndActive;
kCTRegistrationDataStatusInternationalRoaming = 1;
kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN;
*/
}
else if ([notifyname isEqualToString:@"kCTRegistrationCellChangedNotification"])
{
/*
kCTRegistrationGsmCellId = 93204174;
kCTRegistrationGsmLac = 55583;
kCTRegistrationInHomeCountry = 1;
kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN;
*/
}
else if ([notifyname isEqualToString:@"kCTIndicatorRadioTransmitNotification"])
{
/*
kCTRadioTransmitDCHStatus = 1;
*/
}
//int unread=CTSMSMessageGetUnreadCount();
//if (unread>0)
//NSLog(@"未讀短信:%d",unread);
NSLog(@"名字:%@-詳細:%@",notifyname,userInfo);
}
static void signalHandler(int sigraised)
{
printf("\nInterrupted.\n");
exit(0);
}
<span style="font-family:Arial, Verdana, sans-serif;"><span style="white-space: normal;">
</span></span>
執行
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver(ct, NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);
// Handle Interrupts
sig_t oldHandler = signal(SIGINT, signalHandler);
if (oldHandler == SIG_ERR)
{
printf("Could not establish new signal handler");
exit(1);
}
// Run loop lets me catch notifications
printf("Starting run loop and watching for notification.\n");
//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
extern NSString* CTSettingCopyMyPhoneNumber();
+(NSString *) phoneNumber {
NSString *phone = CTSettingCopyMyPhoneNumber();
return phone;
}