10.5 编写tweak

在使用Cycript完成核心功能的测试后,用Theos编写代码就仅仅是简单的体力劳动了。本节,就用最直观的代码,给MobileSMS中的SMSApplication类添加2个实例函数,分别是“-(int)madridStatusForAddress:(NSString*)address”和“-(void)sendMadridMessage ToAddress:(NSString*)address withText:(NSString*)text”,然后用Cycript测试这2个类函数的有效性。开始行动!

10.5.1 用Theos新建tweak工程“iOSREMadridMessenger”

新建iOSREMadridMessenger工程的命令如下:


snakeninnys-MacBook:Code snakeninny$ /opt/theos/bin/nic.pl
NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/application
  [2.] iphone/cydget
  [3.] iphone/framework
  [4.] iphone/library
  [5.] iphone/notification_center_widget
  [6.] iphone/preference_bundle
  [7.] iphone/sbsettingstoggle
  [8.] iphone/tool
  [9.] iphone/tweak
  [10.] iphone/xpc_service
Choose a Template (required): 9
Project Name (required): iOSREMadridMessenger
Package Name [com.yourcompany.iosremadridmessenger]: com.iosre.iosremadridmessenger
Author/Maintainer Name [snakeninny]: snakeninny
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.MobileSMS
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:MobileSMS
Instantiating iphone/tweak in iosremadridmessenger/...
Done.

10.5.2 构造iOSREMadridMessenger.h

在10.2节的检测及10.3节的发送中,用到了私有框架IDS、ChatKit和IMCore中的多个私有类和私有函数,我们必须给出它们的定义,才能避免编译器报错或警告。当然,iOSREMadridMessenger.h的内容并不是凭空构造出来的,所有的定义均来自于class-dump出的头文件,我们只是把用到的东西挑选出来,再整合到一个头文件里而已——我们构造的只是一个“精选头文件”。编辑后的iOSREMadridMessenger.h内容如下:


@interface IDSIDQueryController
+ (instancetype)sharedInstance;
- (NSDictionary *)_currentIDStatusForDestinations:(NSArray*)arg1 service:(NSString *)arg2 listenerID:(NSString *)arg3;
@end
@interface IMServiceImpl : NSObject
+ (instancetype)iMessageService;
@end
@class IMHandle;
@interface IMAccount : NSObject
- (IMHandle *)imHandleWithID:(NSString *)arg1 alreadyCanonical:(BOOL)arg2;
@end
@interface IMAccountController : NSObject
+ (instancetype)sharedInstance;
- (IMAccount *)__ck_defaultAccountForService:(IMServiceImpl*)arg1;
@end
@interface IMMessage : NSObject
+ (instancetype)instantMessageWithText:(NSAttributedString*)arg1 flags:(unsigned long long)arg2;
@end
@interface IMChat : NSObject
- (void)sendMessage:(IMMessage *)arg1;
@end
@interface IMChatRegistry : NSObject
+ (instancetype)sharedInstance;
- (IMChat *)chatForIMHandle:(IMHandle *)arg1;
@end

10.5.3 编辑Tweak.xm

编辑后的Tweak.xm内容如下:


#import "iOSREMadridMessenger.h"
%hook SMSApplication
%new
- (int)madridStatusForAddress:(NSString *)address
{
      NSString *formattedAddress = nil;
     if ([address rangeOfString:@"@"].location != NSNotFound) formattedAddress = [@"mailto:" stringByAppendingString:address];
      else formattedAddress = [@"tel:" stringByAppendingString:address];
    NSDictionary *status = [[IDSIDQueryController sharedInstance] _current IDStatusForDestinations:@[formattedAddress] service:@"com.apple.madrid" listenerID: @"__kIMChatServiceForSendingIDSQueryControllerListenerID"];
      return [status[formattedAddress] intValue];
}
%new
- (void)sendMadridMessageToAddress:(NSString *)address withText:(NSString *)text
{
      IMServiceImpl *service = [IMServiceImpl iMessageService];
      IMAccount *account = [[IMAccountController sharedInstance] __ck_defaultAccountForService:service];
      IMHandle *handle = [account imHandleWithID:address alreadyCanonical:NO];
      IMChat *chat = [[IMChatRegistry sharedInstance] chatForIMHandle:handle];
      NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: text];
     IMMessage *message = [IMMessage instantMessageWithText:attributedString flags: 100005];
      [chat sendMessage:message];
      [attributedString release];
}
%end

10.5.4 编辑Makefile及control

编辑后的Makefile内容如下:


THEOS_DEVICE_IP = iOSIP
ARCHS = armv7 arm64
TARGET = iphone:latest:8.0
include theos/makefiles/common.mk
TWEAK_NAME = iOSREMadridMessenger
iOSREMadridMessenger_FILES = Tweak.xm
iOSREMadridMessenger_PRIVATE_FRAMEWORKS = IDS ChatKit IMCore
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
      install.exec "killall -9 MobileSMS"

编辑后的control内容如下:


Package: com.iosre.iosremadridmessenger
Name: iOSREMadridMessenger
Depends: mobilesubstrate, firmware (>= 8.0)
Version: 1.0
Architecture: iphoneos-arm
Description: Detect and send iMessage example
Maintainer: snakeninny
Author: snakeninny
Section: Tweaks
Homepage: http://bbs.iosre.com

10.5.5 用Cycript测试

将写好的tweak编译打包安装到iOS后,执行ssh命令连接到iOS中,然后执行如下代码:


FunMaker-5:~ root# cycript -p MobileSMS
cy# [UIApp madridStatusForAddress:@"snakeninny@icloud.com"]
1
cy# [UIApp sendMadridMessageToAddress:@"snakeninny@icloud.com" withText:@"Sent from iOSREMadridMessenger"]

“snakeninny@icloud.com”的检测结果是1,支持iMessage,且此条iMessage被成功发送,如图10-98所示。

图10-98 成功发送iMessage

如果你按照上面的思路和方法成功搞定了iMessage的检测和发送,就给“snakeninny@gmail.com”发一条iMessage吧!