当前位置: 首页 > news >正文

使用 CTTeleyphonyCenter 截获来去电及短信消息

无庸置疑,以下的所有操作必须建立在已越狱的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(CFAllocatorRef, CTCall *call); //获得来电号码  第一个参数一般传入kCFAllocatorDefault
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"];

    CFStringRef caller = CTCallCopyAddress(kCFAllocatorDefault, call); // caller 便是来电号码

    CFRelease(caller);

    CTCallDisconnect(call); // 挂断电话

    CTCallAnswer(call); // 接电话

    CTCallGetStatus(CTCall *call); // 获得电话状态 拨出电话时为3,有呼入电话时为4,挂断电话时为5

    CTCallGetGetRowIDOfLastInsert(void); // 获得最近一条电话记录在电话记录数据库(call_history.db)中的位置(ROWID)

  }

}

以上代码经测试可以使用:

测试机型:iPhone 3GS

系统版本:iOS 4.3.3

手机状态:已越狱

测试结果:Perfect!

 

下面我们讲一下如何捕获和拦截短信:

首先我们需要一个名为ChatKit的基础框架,它是一个私有的基础框架。从这个框架中我们可以获得如下消息和键值:

CKServiceMessageReceivedNotification

CKServiceMessageSentNotification

CKMessageKey

与上面的电话消息一样,我们在SpringBoard启动后在CTTelephonyCenter中注册以上的消息:

    CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, callBack, CKServiceMessageReceivedNotification, NULL, CFNotificationSuspensionBehaviorDrop);

然后就是回调函数的实现:

static void callBack(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {

  // 通过以上提到的那个键值CKMessageKey我们可以获得一个类型为CKSMSMessage的       // message, 这个CKSMSMessage也定义在ChatKit这个框架中。message 将为我们提        // 供一个短信的所有属性和内容,然后我们就可以对该短信进行操作了。

  CKSMSMessage *message = [(NSDictionary *)userInfo objectForKey:CKMessageKey];

  // 在各种操作中删除操作是最复杂的,因为它涉及到了系统短信数据库的操作,且各个iOS版本也有不同。下面我们说一下iOS4和iOS5中的短信删除。

  NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
      if ([systemVersion hasPrefix:@"4."]) {
            [[objc_getClass("SBSMSManager") sharedSMSManager] deleteMessage:message deleteConversationIfEmpty:YES];
      } else if ([systemVersion hasPrefix:@"5."]) {
            NSString *address = [message address];
            CKConversation *conversation = [message conversation];
            CKSMSService *service = (CKSMSService *)[conversation service];
            [service deleteMessage:message fromConversation:conversation];
            NSUInteger count = 0;
            sqlite3 *database = NULL;
            if (sqlite3_open(SMSDATABASE, &database) == SQLITE_OK) {
                char *sql = sqlite3_mprintf("SELECT COUNT(*) FROM message WHERE address = \'%s\'", [address UTF8String]);
                sqlite3_stmt *statement = NULL;
                if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
                    while (sqlite3_step(statement) == SQLITE_ROW) {
                        count = (NSUInteger)sqlite3_column_int(statement, 0);
                    }
                    sqlite3_finalize(statement);
                }
                sqlite3_free(sql);
                if (!count) {
                    sql = sqlite3_mprintf("DELETE FROM group_member WHERE address = \'%s\'", [address UTF8String]);
                    sqlite3_exec(database, sql, NULL, NULL, NULL);
                    sqlite3_free(sql);
                }
                
                sqlite3_close(database);
            }
        }

}

以上代码经测试有效,且可以在每个会话中没有内容的时候删除该空会话,但是iOS4中会弹出一个空的短信提醒框,所以感觉不是很完美。

转载于:https://www.cnblogs.com/OtionSky/archive/2011/11/10/iPhone_TelephoneCenter.html

相关文章:

  • 翻译]游戏主循环
  • Ural_1126. Magnetic Storms 单调队列
  • adb shell dumpsys 命令 查看内存
  • hibernate连接Mysql中文乱码处理
  • very_confusing
  • HDOJ4070
  • apche IIS .htaccess httpd.ini Rewrite RewriteRule详解
  • 60个数据窗口技巧(转)
  • Android基础之Android硬件
  • VIM之Project 项目管理工具
  • 复制构造函数与禁止复制即函数值传递的原理
  • 基于MINA构建简单高性能的NIO应用-一个简单的例子
  • 【分析最原始验证码生成】HTTP请求处理程序
  • 托盘程序(WinForm)
  • kindle3 入手感受
  • bearychat的java client
  • Go 语言编译器的 //go: 详解
  • HTTP 简介
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Java超时控制的实现
  • Just for fun——迅速写完快速排序
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • MySQL用户中的%到底包不包括localhost?
  • Python十分钟制作属于你自己的个性logo
  • Redis 中的布隆过滤器
  • SpiderData 2019年2月13日 DApp数据排行榜
  • yii2中session跨域名的问题
  • Zepto.js源码学习之二
  • 测试如何在敏捷团队中工作?
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 前端面试题总结
  • 突破自己的技术思维
  • 我是如何设计 Upload 上传组件的
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • ###STL(标准模板库)
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #pragma once与条件编译
  • #QT(智能家居界面-界面切换)
  • (Oracle)SQL优化技巧(一):分页查询
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (第二周)效能测试
  • (二)fiber的基本认识
  • (转)iOS字体
  • ***利用Ms05002溢出找“肉鸡
  • **CI中自动类加载的用法总结
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net core使用ef 6
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .NET 依赖注入和配置系统
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .Net的C#语言取月份数值对应的MonthName值
  • .NET开发人员必知的八个网站