庸置疑,以下的所有操作必须建立在已越狱的iPhone手机上。 |
02 | 首先,在建立工程之后我们要引入一个名为CoreTelephony.framework的框架,他是一个是一个有关电话、短信和邮件通讯的框架。 |
03 | 注:使用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去得到那些有关的类。 |
04 | 接着,我们要引入一些没有在文档中出现,但又确实存在的函数,由于我们的实现文件为.mm文件所以引入时最好使用 extern "C" 方式: |
05 | extern "C" CFNotificationCenterRef CTTelephonyCenterGetDefault( void ); // 获得 TelephonyCenter (电话消息中心) 的引用 |
06 | extern "C" void CTTelephonyCenterAddObserver(CFNotificationCenterRef center, const void *observer, CFNotificationCallback callBack, CFStringRef name, const void *object, CFNotificationSuspensionBehavior suspensionBehavior); |
07 | extern "C" void CTTelephonyCenterRemoveObserver(CFNotificationCenterRef center, const void *observer, CFStringRef name, const void *object); |
08 | extern "C" NSString *CTCallCopyAddress( void *, CTCall *call); //获得来电号码 |
09 | extern "C" void CTCallDisconnect(CTCall *call); // 挂断电话 |
10 | extern "C" void CTCallAnswer(CTCall *call); // 接电话 |
11 | extern "C" void CTCallAddressBlocked(CTCall *call); |
12 | extern "C" int CTCallGetStatus(CTCall *call); // 获得电话状态 拨出电话时为3,有呼入电话时为4,挂断电话时为5 |
13 | extern "C" int CTCallGetGetRowIDOfLastInsert( void ); // 获得最近一条电话记录在电话记录数据库中的位置 |
14 | 以上这些方法都在CoreTelephony这个库中实现,这也是为什么我们要一开始就引入这个框架了。 |
15 | 第三步:我们就要是要在SpringBaord启动之后就将我们的回调函数注册到CTTelephonyCenter这个消息中心,注册我们就放在Hook到SpringBoard的applicationDidFinishLaunching:的那个函数中去: |
16 | CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, &callBack, CFSTR( "kCTCallStatusChangeNotification" ), NULL, CFNotificationSuspensionBehaviorHold); |
17 | |
18 | 这里用到的CTTelephonyCenterAddObsever这个函数基本上与文档中给出的CFNotificationCenterAddObserver这个函数一样,所以我们可以参照后者对前者进行使用(经我测试用法基本相同)。 |
19 | 最后,就是对回调函数的实现: |
20 | static void callBack(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { |
21 | if ([(NSString *)name isEqualToString:@ "kCTCallStatusChangeNotification" ]) { |
22 | CTCall *call = (CTCall *)[(NSDictionary *)userInfo objectForKey:@ "kCTCall" ]; |
23 | NSString *caller = CTCallCopyAddress(NULL, call); // caller 便是来电号码 |
24 | CTCallDisconnect(call); // 挂断电话 |
25 | CTCallAnswer(call); // 接电话 |
26 | CTCallGetStatus(CTCall *call); // 获得电话状态 拨出电话时为3,有呼入电话时为4,挂断电话时为5 |
27 | CTCallGetGetRowIDOfLastInsert( void ); // 获得最近一条电话记录在电话记录数据库(call_history.db)中的位置(ROWID) |
28 | } |
29 | } |
30 | 以上代码经测试可以使用: |
31 | 测试机型:iPhone 3GS |
32 | 系统版本:iOS 4.3.3 |
33 | 手机状态:已越狱 |
34 | 测试结果:Perfect! |
35 | |
36 | 下面我们讲一下如何捕获和拦截短信: |
37 | 首先我们需要一个名为ChatKit的基础框架,它是一个私有的基础框架。从这个框架中我们可以获得如下消息和键值: |
38 | CKServiceMessageReceivedNotification |
39 | CKServiceMessageSentNotification |
40 | CKMessageKey |
41 | 与上面的电话消息一样,我们在SpringBoard启动后在CTTelephonyCenter中注册以上的消息: |
42 | CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, callBack, CKServiceMessageReceivedNotification, NULL, CFNotificationSuspensionBehaviorDrop); |
43 | 然后就是回调函数的实现: |
44 | static void callBack(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { |
45 | // 通过以上提到的那个键值CKMessageKey我们可以获得一个类型为CKSMSMessage的 // message, 这个CKSMSMessage也定义在ChatKit这个框架中。message 将为我们提 // 供一个短信的所有属性和内容,然后我们就可以对该短信进行操作了。 |
46 | CKSMSMessage *message = [(NSDictionary *)userInfo objectForKey:CKMessageKey]; |
47 | // 在各种操作中删除操作是最复杂的,因为它涉及到了系统短信数据库的操作,且各个iOS版本也有不同。下面我们说一下iOS4和iOS5中的短信删除。 |
48 | NSString *systemVersion = [[UIDevice currentDevice] systemVersion]; |
49 | if ([systemVersion hasPrefix:@ "4." ]) { |
50 | [[objc_getClass( "SBSMSManager" ) sharedSMSManager] deleteMessage:message deleteConversationIfEmpty:YES]; |
51 | } else if ([systemVersion hasPrefix:@ "5." ]) { |
52 | NSString *address = [message address]; |
53 | CKConversation *conversation = [message conversation]; |
54 | CKSMSService *service = (CKSMSService *)[conversation service]; |
55 | [service deleteMessage:message fromConversation:conversation]; |
56 | NSUInteger count = 0; |
57 | sqlite3 *database = NULL; |
58 | if (sqlite3_open(SMSDATABASE, &database) == SQLITE_OK) { |
59 | char *sql = sqlite3_mprintf( "SELECT COUNT(*) FROM message WHERE address = \'%s\'" , [address UTF8String]); |
60 | sqlite3_stmt *statement = NULL; |
61 | if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) { |
62 | while (sqlite3_step(statement) == SQLITE_ROW) { |
63 | count = (NSUInteger)sqlite3_column_int(statement, 0); |
64 | } |
65 | sqlite3_finalize(statement); |
66 | } |
67 | sqlite3_free(sql); |
68 | if (!count) { |
69 | sql = sqlite3_mprintf( "DELETE FROM group_member WHERE address = \'%s\'" , [address UTF8String]); |
70 | sqlite3_exec(database, sql, NULL, NULL, NULL); |
71 | sqlite3_free(sql); |
72 | } |
73 | |
74 | sqlite3_close(database); |
75 | } |
76 | } |
77 | } |
78 | 以上代码经测试有效,且可以在每个会话中没有内容的时候删除该空会话,但是iOS4中会弹出一个空的短信提醒框,所以感觉不是很完美。 |