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. (转载)mysql:设置mysql的远程访问

    1.登陆Mysqlmysql -u root -p2.允许任何IP访问,其中密码为admingrant all privileges on *.* to root@"%" iden ...

  2. Chrome插件 postman的使用方法详解!最全面的教程

    一 简介 Postman 是一款功能超级强大的用于发送 HTTP 请求的 Chrome插件 .做web页面开发和测试的人员应该是无人不晓无人不用!其主要特点 特点: 创建 + 测试:创建和发送任何的H ...

  3. activiti流程跟踪图算法

    流程跟踪图-推导算法 工作中使用activiti实现流程图相关业务,但是上线后遇到问题,偶尔流程图出不来.查阅了一下画流程图的实现,基本上是参见:activiti-流程图颜色变化之一篇. 核心类,参见 ...

  4. dede列表页读取当前栏目名称

    list或者arclist之内使用[field:typename/]之外使用{dede:field name='typename'/}

  5. SVN服务器搭建和使用-转载

    SVN服务器搭建和使用(一)-转载 原文地址:http://www.cnblogs.com/xiaobaihome/archive/2012/03/20/2407610.html Subversion ...

  6. Shell 利用 curl 模拟登陆

    -b 参数 指定使用cookie文件 -c是往cookie文件中写cookie -d 是指定此次登录所需的参数,通过httpfox查看 -L 指定页面自动跳转 #curl -c ck.txt --us ...

  7. foxmail占cpu 100%解决办法

    Win10,x64 Foxmail 7.2.9.075 解决办法: 1. 删除文件夹 d:\Program Files\Foxmail\Storage\邮箱\Indexes2. 菜单 –>帮助 ...

  8. 上海高校金马五校赛 J - 小Y写文章

    题目大意: 给你n个数字, 定义不连贯值为, max(abs(a[ i ] - b[ i ])) ,现在让你把m个新的数字插入n + 1 个空位中,使得不连贯值最小. 思路:二分不连贯值, 每次进行二 ...

  9. R语言编程艺术(5)R语言编程进阶

    本文对应<R语言编程艺术> 第14章:性能提升:速度和内存: 第15章:R与其他语言的接口: 第16章:R语言并行计算 ================================== ...

  10.  sublime text3快速生成html头部信息(转)

    sublime text3快速生成html头部信息  https://blog.csdn.net/sunshinegirl_7/article/details/49802579 经常见别人创建新的ht ...