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 plaincopy

 
  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. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  27. // printf("NOTIFICATION: %s\n", [name UTF8String]);
  28. if (!userInfo) return;
  29. NSDictionary *info = (NSDictionary*)userInfo;
  30. int dcount = CFDictionaryGetCount(userInfo);
  31. id keys = [(NSDictionary*)userInfo allKeys];
  32. int i;
  33. for (i = 0; i < dcount; i++)
  34. {
  35. id key = [keys objectAtIndex:i];
  36. dolog(@"  %@: %@", key, [info objectForKey:key]);
  37. }
  38. if ([[(NSDictionary *)userInfo allKeys]
  39. containsObject:@"kCTSMSMessage"]) // SMS Message
  40. {
  41. CTSMSMessage *message = (CTSMSMessage *)
  42. [(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];
  43. NSString *address = CTSMSMessageCopyAddress(NULL, message);
  44. NSString *text = CTSMSMessageCopyText(NULL, message);
  45. NSArray *lines = [text componentsSeparatedByString:@"\n"];
  46. printf("  %s %d\n", [address cString], [lines count]);
  47. printf("  %s\n", [text cString]);
  48. fflush(stdout);
  49. }
  50. [pool release];
  51. return ;
  52. }
  53. static void signalHandler(int sigraised)
  54. {
  55. printf("\nInterrupted.\n");
  56. exit(0);
  57. }
  58. int main(int argc, char **argv)
  59. {
  60. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  61. // Initialize listener by adding CT Center observer implicit
  62. id ct = CTTelephonyCenterGetDefault();
  63. CTTelephonyCenterAddObserver( ct, NULL, callback,NULL,NULL,
  64. CFNotificationSuspensionBehaviorHold);
  65. // Handle Interrupts
  66. sig_t oldHandler = signal(SIGINT, signalHandler);
  67. if (oldHandler == SIG_ERR)
  68. {
  69. printf("Could not establish new signal handler");
  70. exit(1);
  71. }
  72. // Run loop lets me catch notifications
  73. printf("Starting run loop and watching for notification.\n");
  74. CFRunLoopRun();
  75. // Shouldn't ever get here. Bzzzt
  76. printf("Unexpectedly back from CFRunLoopRun()!\n");
  77. [pool release];
  78. }

2.

[cpp] view plaincopy

 
  1. extern NSString* const kCTSMSMessageReceivedNotification;
  2. extern NSString* const kCTSMSMessageReplaceReceivedNotification;
  3. extern NSString* const kCTSIMSupportSIMStatusNotInserted;
  4. extern NSString* const kCTSIMSupportSIMStatusReady;
  5. typedef struct __CTCall CTCall;
  6. extern NSString *CTCallCopyAddress(void*, CTCall *);
  7. void* CTSMSMessageSend(id server,id msg);
  8. typedef struct __CTSMSMessage CTSMSMessage;
  9. NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *);
  10. NSString *CTSMSMessageCopyText(void *, CTSMSMessage *);
  11. int CTSMSMessageGetRecordIdentifier(void * msg);
  12. NSString * CTSIMSupportGetSIMStatus();
  13. NSString * CTSIMSupportCopyMobileSubscriberIdentity();
  14. id  CTSMSMessageCreate(void* unknow/*always 0*/,NSString* number,NSString* text);
  15. void * CTSMSMessageCreateReply(void* unknow/*always 0*/,void * forwardTo,NSString* text);
  16. id CTTelephonyCenterGetDefault(void);
  17. void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);
  18. void CTTelephonyCenterRemoveObserver(id,id,NSString*,void*);
  19. int CTSMSMessageGetUnreadCount(void);
  20. static void callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
  21. {
  22. NSString *notifyname=(NSString *)name;
  23. if ([notifyname isEqualToString:@"kCTCallStatusChangeNotification"])//电话
  24. {
  25. NSDictionary *info = (NSDictionary*)userInfo;
  26. NSString *state=[[info objectForKey:@"kCTCallStatus"] stringValue];
  27. if ([state isEqualToString:@"5"])//disconnect
  28. NSLog(@"未接:%@",state);
  29. }
  30. else if ([notifyname isEqualToString:@"kCTCallIdentificationChangeNotification"])
  31. {
  32. //        CTCallCenter *center = [[CTCallCenter alloc] init];
  33. //        center.callEventHandler = ^(CTCall *call) {
  34. //            NSLog(@"call:%@", [call description]);
  35. //        };
  36. NSDictionary *info = (NSDictionary *)userInfo;
  37. CTCall *call = (CTCall *)[info objectForKey:@"kCTCall"];
  38. NSString *caller = CTCallCopyAddress(NULL, call);
  39. NSLog(@"电话号码:%@",caller);
  40. //CTCallDisconnect(call);
  41. /* or one of the following functions: CTCallAnswer
  42. CTCallAnswerEndingActive
  43. CTCallAnswerEndingAllOthers
  44. CTCallAnswerEndingHeld
  45. */
  46. }
  47. else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])
  48. {
  49. }
  50. else if ([notifyname isEqualToString:@"kCTSMSMessageReceivedNotification"])
  51. {//api 已过期
  52. if ([[(NSDictionary *)userInfo allKeys]
  53. containsObject:@"kCTSMSMessage"]) // SMS Message
  54. {
  55. CTSMSMessage *message = (CTSMSMessage *)
  56. [(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"];
  57. NSString *address = CTSMSMessageCopyAddress(NULL, message);
  58. NSString *text = CTSMSMessageCopyText(NULL, message);
  59. //NSArray *lines = [text componentsSeparatedByString:@"\n"];
  60. //printf("  %s %d\n", [address cString], [lines count]);
  61. //printf("  %s\n", [text cString]);
  62. fflush(stdout);
  63. }
  64. }
  65. else if ([notifyname isEqualToString:@"kCTMessageReceivedNotification"])//收到短信
  66. {
  67. /*
  68. kCTMessageIdKey = "-2147483636";
  69. kCTMessageTypeKey = 1;
  70. */
  71. NSDictionary *info = (NSDictionary *)userInfo;
  72. CFNumberRef msgID = (CFNumberRef)[info objectForKey:@"kCTMessageIdKey"];
  73. int result;
  74. CFNumberGetValue((CFNumberRef)msgID, kCFNumberSInt32Type, &result);
  75. /*
  76. Class CTMessageCenter = NSClassFromString(@"CTMessageCenter");
  77. id mc = [CTMessageCenter sharedMessageCenter];
  78. id incMsg = [mc incomingMessageWithId: result];
  79. int msgType = (int)[incMsg messageType];
  80. if (msgType == 1) //experimentally detected number
  81. {
  82. id phonenumber = [incMsg sender];
  83. NSString *senderNumber = (NSString *)[phonenumber canonicalFormat];
  84. id incMsgPart = [[incMsg items] objectAtIndex:0];
  85. NSData *smsData = [incMsgPart data];
  86. NSString *smsText = [[NSString alloc] initWithData:smsData encoding:NSUTF8StringEncoding];
  87. }
  88. */
  89. }
  90. else if ([notifyname isEqualToString:@"kCTIndicatorsSignalStrengthNotification"])//信号
  91. {
  92. /*
  93. kCTIndicatorsGradedSignalStrength = 2;
  94. kCTIndicatorsRawSignalStrength = "-101";
  95. kCTIndicatorsSignalStrength = 19;
  96. */
  97. }
  98. else if ([notifyname isEqualToString:@"kCTRegistrationStatusChangedNotification"])//网络注册状态
  99. {
  100. /*
  101. kCTRegistrationInHomeCountry = 1;
  102. kCTRegistrationStatus = kCTRegistrationStatusRegisteredHome;
  103. */
  104. }
  105. else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"])
  106. {
  107. /*
  108. kCTRegistrationDataActive = 1;
  109. kCTRegistrationDataAttached = 1;
  110. kCTRegistrationDataConnectionServices =     (
  111. kCTDataConnectionServiceTypeInternet,
  112. kCTDataConnectionServiceTypeWirelessModemTraffic,
  113. kCTDataConnectionServiceTypeWirelessModemAuthentication
  114. );
  115. kCTRegistrationDataContextID = 0;
  116. kCTRegistrationDataIndicator = kCTRegistrationDataIndicator3G;
  117. kCTRegistrationDataStatus = kCTRegistrationDataStatusAttachedAndActive;
  118. kCTRegistrationDataStatusInternationalRoaming = 1;
  119. kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN;
  120. */
  121. }
  122. else if ([notifyname isEqualToString:@"kCTRegistrationCellChangedNotification"])
  123. {
  124. /*
  125. kCTRegistrationGsmCellId = 93204174;
  126. kCTRegistrationGsmLac = 55583;
  127. kCTRegistrationInHomeCountry = 1;
  128. kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN;
  129. */
  130. }
  131. else if ([notifyname isEqualToString:@"kCTIndicatorRadioTransmitNotification"])
  132. {
  133. /*
  134. kCTRadioTransmitDCHStatus = 1;
  135. */
  136. }
  137. //int unread=CTSMSMessageGetUnreadCount();
  138. //if (unread>0)
  139. //NSLog(@"未读短信:%d",unread);
  140. NSLog(@"名字:%@-详细:%@",notifyname,userInfo);
  141. }
  142. static void signalHandler(int sigraised)
  143. {
  144. printf("\nInterrupted.\n");
  145. exit(0);
  146. }
  147. <span style="font-family:Arial, Verdana, sans-serif;"><span style="white-space: normal;">
  148. </span></span>

执行

[cpp] view plaincopy

 
  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. +(NSString *) phoneNumber {
  3. NSString *phone = CTSettingCopyMyPhoneNumber();
  4. return phone;
  5. }

整理:iOS 短信与电话事件的获取的更多相关文章

  1. ios短信和电话--参考

    调用打电话功能 [[UIApplicationsharedApplication] openURL:[NSURL URLWithString:@"tel://10086"]]; 调 ...

  2. zabbix3.0 安装方法,一键实现短信、电话、微信、APP 告警

    引言 免费开源监控工具 Zabbix 因其强大的监控功能得到各大互联网公司的广泛认可,具体功能不再详细介绍,在之前发布的 Zabbix 2.4.1 安装及微信短信提醒已经做了详细介绍,本篇主要对 Za ...

  3. Auto.js 调用系统短信、电话

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js 调用系统短信.电话 操作 ...

  4. 【Android学习】调用系统短信、电话

    今天全心投入Android学习已经有一段时间了,从起初的啥也不懂,到现在半知半解状态,随笔记录些简单且常用的系统功能代码. 调用Android系统短信,其实调用短信非常简单,一个方法就可以搞定.我们可 ...

  5. iOS使用技能 - 短信,语言验证码的获取与验证小结

    最近有学习一个小技能,这里小结一下,分享给大家,互相交流. 首先是大体步骤: 在mob官网注册,然后添加短信验证的应用 使用cocoapods导入框架 Podfile文件: platform :ios ...

  6. prometheus grafana graylog 钉钉告警 短信告警 电话告警系统 PrometheusAlert

    PrometheusAlert 简介 PrometheusAlert是开源的运维告警中心消息转发系统,支持主流的监控系统Prometheus,日志系统Graylog和数据可视化系统Grafana发出的 ...

  7. iOS 短信分享 邮件分享

    本地调用短信分享. #import "shareViewController.h" @interface shareViewController (){ UIAlertView * ...

  8. day80:luffy:短信sdk接入&点击获取验证码&注册功能的实现&Celery实现短信发送功能

    目录 1.短信sdk接入 2.前端点击获取验证码效果 3.注册后端接口实现 4.注册-前端 5.Celery 6.Celery完成短信发送功能 1.短信sdk接入 1.准备工作 1.下载云通讯相关的文 ...

  9. BroadcoastReceiver之短信到来监听和获取内容

    废话就不说了,新建类继承,然后配置Manifest.xml:如下 <!--需要给一个接收短信的权限 --> <uses-permission android:name="a ...

随机推荐

  1. Go语言规格说明书 之 词汇元素(Lexical elements)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...

  2. 使用 Gradle 对应用进行个性化定制

    啥也不说了,直接进入主题吧.本篇文章主要根据实际开发中遇到的需求,讲解使用 Gradle 对应用的不同版本进行个性化定制. 场景介绍 一般的应用基本上都有正式服和测试服,这个就不需要多说了.但是有些应 ...

  3. ICCV2013 录用论文(目标跟踪相关部分)(转)

    单目标(表观模型): 1. Seunghoon Hong, BohyungHan. Orderless Trackingthrough Model-Averaged Density Estimatio ...

  4. dede列表页调用

    {dede:list pagesize ='16'} <li class="item pull-left"> <a class="item-wrap&q ...

  5. Ubuntu 12.04 下 Sublime Text 3 Build 3047 破解

    1. $sudo vim /opt/sublime_text/sublime_text 2. 将文件转成十六进制形式.在 vim 中输入: :%!xxd 3. 查找数字串 “4333 3342 303 ...

  6. HDOJ题目分类

    模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...

  7. WinForm1

    一.窗体的各种属性 二.控件 1.公共控件 2.容器控件 3.菜单控件

  8. C语言:指针实现交换两个变量的值

    用指针交换两个变量的值(10分) 题目内容: 用指针交换两个变量的值 主函数参考: int main( ) { int a,b; scanf("%d%d",&a,& ...

  9. # Java反射2——获取实体所有属性和方法,并对属性赋值

    1.一个普通的实体Person: private int id; private String name; private Date createdTime; ... //其它字段 // get se ...

  10. 循序渐进学.Net Core Web Api开发系列【5】:文件上传

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍通 ...