整理:iOS 短信与电话事件的获取
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。
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;
- }
整理:iOS 短信与电话事件的获取的更多相关文章
- ios短信和电话--参考
调用打电话功能 [[UIApplicationsharedApplication] openURL:[NSURL URLWithString:@"tel://10086"]]; 调 ...
- zabbix3.0 安装方法,一键实现短信、电话、微信、APP 告警
引言 免费开源监控工具 Zabbix 因其强大的监控功能得到各大互联网公司的广泛认可,具体功能不再详细介绍,在之前发布的 Zabbix 2.4.1 安装及微信短信提醒已经做了详细介绍,本篇主要对 Za ...
- Auto.js 调用系统短信、电话
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js 调用系统短信.电话 操作 ...
- 【Android学习】调用系统短信、电话
今天全心投入Android学习已经有一段时间了,从起初的啥也不懂,到现在半知半解状态,随笔记录些简单且常用的系统功能代码. 调用Android系统短信,其实调用短信非常简单,一个方法就可以搞定.我们可 ...
- iOS使用技能 - 短信,语言验证码的获取与验证小结
最近有学习一个小技能,这里小结一下,分享给大家,互相交流. 首先是大体步骤: 在mob官网注册,然后添加短信验证的应用 使用cocoapods导入框架 Podfile文件: platform :ios ...
- prometheus grafana graylog 钉钉告警 短信告警 电话告警系统 PrometheusAlert
PrometheusAlert 简介 PrometheusAlert是开源的运维告警中心消息转发系统,支持主流的监控系统Prometheus,日志系统Graylog和数据可视化系统Grafana发出的 ...
- iOS 短信分享 邮件分享
本地调用短信分享. #import "shareViewController.h" @interface shareViewController (){ UIAlertView * ...
- day80:luffy:短信sdk接入&点击获取验证码&注册功能的实现&Celery实现短信发送功能
目录 1.短信sdk接入 2.前端点击获取验证码效果 3.注册后端接口实现 4.注册-前端 5.Celery 6.Celery完成短信发送功能 1.短信sdk接入 1.准备工作 1.下载云通讯相关的文 ...
- BroadcoastReceiver之短信到来监听和获取内容
废话就不说了,新建类继承,然后配置Manifest.xml:如下 <!--需要给一个接收短信的权限 --> <uses-permission android:name="a ...
随机推荐
- 三、vue脚手架工具vue-cli的使用
1.vue-cli构建 vue-cli工具构建:https://blog.csdn.net/u013182762/article/details/53021374 npm的镜像替换成淘宝 2.项目运行 ...
- vs 连接过程报错 dll 分析 ------- DLL动态链接库
1:编译成功,说明代码没有问题了2:连接报错,说明 exe 在查找dll 的入口地址过程,找不到合适的信息,这些信息保存在 dll 对应的 *.lib 文件里面 说明:exe如果生成成功了lib 这 ...
- dataframe 差集
>>>data_a={'state':[1,1,2],'pop':['a','b','c']}>>>data_b={'state':[1,2,3],'pop':[' ...
- jQuery-介绍
一:什么是jQuery jQuery 是一个 JavaScript 库. 二:安装 http://jquery.com/download/ http://jquery.cuishifeng.cn/ j ...
- Ocelot + IdentityServer4 构建 GateWay
上一篇已经构建好了例子,接下来将IdentityServer4添加到Ocelot中去实现 配置一个客户端配置,可以构建一个简单的客户端信息,这里我用的混合模式,配置比较多,对于客户端模式而言实际很多都 ...
- miniblink+golang开发windows gui应用
golang的优点自不必说了,这么好的语言怎么能缺少界面库呢?所以我使用miniblink开发了一个可以用html,css,js开发界面的浏览器,通过它你能为你的golang开发简单的界面.说白了其实 ...
- 配置SSH服务使用证书登录Ubuntu服务器
根据项目要求,需要将项目迁移到Linux系统上,作为测试,选用的是阿里云服务器,1核CPU,1G内存(没错就是这么穷),操作系统Ubuntu 16.04 64位.当然其实如果使用阿里云服务器其实是不需 ...
- P1203 [USACO1.1]坏掉的项链Broken Necklace
P1203 [USACO1.1]坏掉的项链Broken Necklace不错的断环为链的模拟题,开成三倍,有很多细节要考虑,比如总长度要<=n,开头第一个是w等等. #include<bi ...
- 001.FTP简介及相关文件
一 FTP简介 FTP(File Transfer Protocol)文件传输协议,用于Internet上控制文件的双向传输. 下载:远程主机拷贝文件至本地: 上传:本地主机拷贝文件至远程. 二 FT ...
- 迈出第一步,Hexo博客搭建
很早之前看到别人的博客就总想着自己之后也要搭一个,最近突然来了干劲,就开始搭起了博客.不过搭博客还真是一个累活,失败了不下十次,用了好几天的时间,感觉自己在浪费时间,但是看到现在博客终于能用了,非常开 ...