庸置疑,以下的所有操作必须建立在已越狱的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中会弹出一个空的短信提醒框,所以感觉不是很完美。
|