整理: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 ...
随机推荐
- (转载)mysql:设置mysql的远程访问
1.登陆Mysqlmysql -u root -p2.允许任何IP访问,其中密码为admingrant all privileges on *.* to root@"%" iden ...
- Chrome插件 postman的使用方法详解!最全面的教程
一 简介 Postman 是一款功能超级强大的用于发送 HTTP 请求的 Chrome插件 .做web页面开发和测试的人员应该是无人不晓无人不用!其主要特点 特点: 创建 + 测试:创建和发送任何的H ...
- activiti流程跟踪图算法
流程跟踪图-推导算法 工作中使用activiti实现流程图相关业务,但是上线后遇到问题,偶尔流程图出不来.查阅了一下画流程图的实现,基本上是参见:activiti-流程图颜色变化之一篇. 核心类,参见 ...
- dede列表页读取当前栏目名称
list或者arclist之内使用[field:typename/]之外使用{dede:field name='typename'/}
- SVN服务器搭建和使用-转载
SVN服务器搭建和使用(一)-转载 原文地址:http://www.cnblogs.com/xiaobaihome/archive/2012/03/20/2407610.html Subversion ...
- Shell 利用 curl 模拟登陆
-b 参数 指定使用cookie文件 -c是往cookie文件中写cookie -d 是指定此次登录所需的参数,通过httpfox查看 -L 指定页面自动跳转 #curl -c ck.txt --us ...
- foxmail占cpu 100%解决办法
Win10,x64 Foxmail 7.2.9.075 解决办法: 1. 删除文件夹 d:\Program Files\Foxmail\Storage\邮箱\Indexes2. 菜单 –>帮助 ...
- 上海高校金马五校赛 J - 小Y写文章
题目大意: 给你n个数字, 定义不连贯值为, max(abs(a[ i ] - b[ i ])) ,现在让你把m个新的数字插入n + 1 个空位中,使得不连贯值最小. 思路:二分不连贯值, 每次进行二 ...
- R语言编程艺术(5)R语言编程进阶
本文对应<R语言编程艺术> 第14章:性能提升:速度和内存: 第15章:R与其他语言的接口: 第16章:R语言并行计算 ================================== ...
- sublime text3快速生成html头部信息(转)
sublime text3快速生成html头部信息 https://blog.csdn.net/sunshinegirl_7/article/details/49802579 经常见别人创建新的ht ...