8.4 编写tweak

在搭建tweak原型的阶段,所有的难点都已被一一攻破,正式编写tweak时只需要简单地整理一下8.3节的结论,就可以得出的漂亮的代码了。

8.4.1 用Theos新建tweak工程“iOSREMailMarker”

新建iOSREMailMarker工程的命令如下:


hangcom-mba:Documents sam$ /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): iOSREMailMarker
Package Name [com.yourcompany.iosremailmarker]: com.iosre.mailmarker
Author/Maintainer Name [sam]: sam
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.mobilemail
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: MobileMail
Instantiating iphone/tweak in iosremailmarker/...
Done.

8.4.2 构造iOSREMailMarker.h

编辑后的iOSREMailMarker.h内容如下:


@interface MailboxPickerController : UITableViewController
@end
@interface NSConcreteNotification : NSNotification
@end
@interface MessageMegaMall : NSObject
- (void)markMessagesAsViewed:(NSSet *)arg1;
- (NSSet *)copyAllMessages;
@end
@interface MFMessageInfo : NSObject
@property (nonatomic) BOOL read;
@end
@interface MFLibraryMessage : NSObject
- (NSArray *)senders;
- (MFMessageInfo *)copyMessageInfo;
@end

这个头文件的所有内容均摘自类对应的头文件,构造它的目的仅仅是通过编译,避免出现任何报错信息和警告。

8.4.3 编辑Tweak.xm

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


#import "iOSREMailMarker.h"
%hook MailboxPickerController
%new
- (void)iOSREShowWhitelist
{
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Whitelist" message:@"Please input an email address" preferredStyle:UIAlertControllerStyleAlert];
      UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlert ActionStyleDefault handler:^(UIAlertAction * action) {
            UITextField *whitelistField = alertController.textFields.firstObject;
            if ([whitelistField.text length] != 0) [[NSUserDefaults standardUser Defaults] setObject:whitelistField.text forKey:@"whitelist"];
      }];
      UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style: UIAlertActionStyleCancel handler:nil];
      [alertController addAction:okAction];
      [alertController addAction:cancelAction];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
            textField.placeholder = @"snakeninny@gmail.com";
            textField.text = [[NSUserDefaults standardUserDefaults] objectForKey: @"whitelist"];
      }];
      [self presentViewController:alertController animated:YES completion:nil];
}
- (void)viewWillAppear:(BOOL)arg1
{
    self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWith Title: @"Whitelist" style:UIBarButtonItemStylePlain target:self action:@selector(iOSREShowWhitelist)] autorelease];
      %orig;
}
%end
%hook MailboxContentViewController
- (void)megaMallMessageCountChanged:(NSConcreteNotification *)arg1
{
      %orig;
      NSMutableSet *targetMessages = [NSMutableSet setWithCapacity:600];
      NSString *whitelist = [[NSUserDefaults standardUserDefaults] objectForKey: @"whitelist"];
      MessageMegaMal *mall = [arg1 object];
      NSSet *messages = [mall copyAllMessages]; // Remember to release it later
      for (MFLibraryMessage *message in messages)
      {
            MFMessageInfo *messageInfo = [message copyMessageInfo]; // Remember to release it later
            for (NSString *sender in [message senders]) if (!messageInfo.read && [sender rangeOfString:[NSString stringWithFormat:@"<%@>", whitelist]].location == NSNotFound) [targetMessages addObject:message];
            [messageInfo release];
      }
      [messages release];
      [mall markMessagesAsViewed:targetMessages];
}
%end

8.4.4 编辑Makefile及control

编辑后的Makefile内容如下:


THEOS_DEVICE_IP = iOSIP
ARCHS = armv7 arm64
TARGET = iphone:latest:8.0
include theos/makefiles/common.mk
TWEAK_NAME = iOSREMailMarker
iOSREMailMarker_FILES = Tweak.xm
iOSREMailMarker_FRAMEWORKS = UIKit
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
      install.exec "killall -9 MobileMail"

编辑后的control内容如下:


Package: com.iosre.mailmarker
Name: iOSREMailMarker
Depends: mobilesubstrate, firmware (>= 8.0)
Version: 1.0
Architecture: iphoneos-arm
Description: Mark non-whitelist emails as read!
Maintainer: sam
Author: sam
Section: Tweaks
Homepage: http://bbs.iosre.com

8.4.5 测试

将写好的tweak编译打包安装到iOS后,打开Mail,因为还没配置iOSREMailMarker,所以Mail跟以前没什么两样。此时,收件箱里一共有44封未读邮件,如图8-18所示。

进入Mailboxes界面,左上角新增了一个“Whitelist”按钮。点击它,弹出一个白名单编辑对话框,如图8-19所示。

图8-18 iOSREMailMarker未配置时的Mail

图8-19 白名单编辑对话框

笔者订阅了一份纽约时报,每天都会花上15分钟左右了解当日时事。把纽约时报的订阅邮箱地址加入白名单,如图8-20所示。

最后给自己发一封邮件,触发megaMallMessageCountChanged:函数。在成功收到这封邮件后,除了纽约时报以外的所有邮件均被标记为已读,收件箱里只剩1封来自纽约时报的未读邮件,如图8-21所示。

图8-20 把纽约时报的订阅邮箱地址加入白名单

图8-21 iOSREMailMarker将纽约时报以外的邮件标记为已读

本章任务圆满结束。