theos资料
- 目录结构:https://github.com/theos/theos/wiki/Structure
- 环境变量:http://iphonedevwiki.net/index.php/Theos
- Logos语法:http://iphonedevwiki.net/index.php/Logos
%hook 和 %end:hook 一个类的开始与结束
%log:打印方法调用详情。可以通过 Xcode - Window - Devices and Simulators
查看日志
HBDebugLog:跟 NSLog 类似
%new:添加一个新的方法,相当于 class_addMethod
,如果直接调用 %new
新增的方法,需要在 @interface
中声明一下。
%c(ClassName):生成一个 Class 对象,相当于 objc_getClass
%orig:函数原来的代码逻辑
%ctor:加载动态库时调用
%dtor:退出程序时调用
logify.pl:可以将一个头文件快速转换成已经包含打印信息的 .xm 文件
logify.pl使用
先将头文件转换为 .xm 文件:
logify.pl xxx.h > xx.xm
然后需要进行一些处理才能编译通过:
删掉关键字 __weak
和 inout
删掉方法 -(void).cxx_destruct {%log; %orig;}
将 HBLogDebug(@"x%x",(unsigned int)r);
改为 HBLogDebug(@"x%@",(unsigned int)r);
将 id<协议名>
改为 id
,或者声明缺少的协议 @protocol 协议名;
将 类名 *
改为 void *
,或者声明缺少的类 @class 类名;
项目资源
Tweak 工程的图片、plist配置文件等资源需要存放在特定目录下,才能正常安装到手机上。
在工程根目录创建 layout
目录,相当于手机的根目录。一般系统插件(在系统的设置里有入口,比如 Reveal Loader)的资源文件会放在 layout/Library/PreferenceLoader/Preferences
目录下,为了不和其他插件的资源冲突,最好是再创建一个只存放自己资源的目录。
比如我们创建的目录为:layout/Library/PreferenceLoader/Preferences/JFXXXXXX
。
则在代码中引用资源的绝对路径为:/Library/PreferenceLoader/Preferences/JFXXXXXX
。
如果是 MonkeyDev
创建的 Logos Tweak
工程,则 Package
目录相当于手机的根目录:
多文件开发
在项目根目录创建 src 目录用于存放我们所有源代码,然后再在 src 下创建我们需要的目录结构,并且需要在 Makefile
文件中指定参与编译的源文件,指定时支持通配符,多个以空格分隔。
当我们在 .x 文件中导入我们创建的 .h 头文件时,请以当前 .x 文件当前目录为基准。
比如根目录下的 src 目录里的所有 .x 文件参与编译:
xxx_FILES = $(wildcard src/*.x)
一些小细节
1.和 iOS 正向开发一样,使用 NSUserDefaults
来保存一些简单配置,这样最终保存的 plist 文件也是在对应 APP 的沙盒目录下。
2.使用 self
调用方法,需要前向声明。self 在此处会被认为是 id 类型,而 numberOfSectionsInTableView:
方法属于 WCTableViewManager
类的方法,如果不对 WCTableViewManager
进行前向声明,是无法调用 numberOfSectionsInTableView:
的。
Tweak.x:12:18: error: receiver type 'WCTableViewManager' for instance message is a forward declaration
if (section == [self numberOfSectionsInTableView:tableView] - 1) {
^~~~
Tweak.x:24:8: note: forward declaration of class here
@class WCTableViewManager;
前向声明代码:
@interface WCTableViewManager
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
@end
3.未导入头文件会提示未知类型,需要导入对应的头文件:
Tweak.x:25:20: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int]
static NSInteger (*_logos_orig$_ungrouped$WCTableViewManager$numberOfSectionsInTableView$)(_LOGOS_SELF_TYPE_NORMAL WCTableViewManager* _LOGOS_SELF_CONST, SEL, UITableView *); static NSInteger _logos_method$_un...
^
Tweak.x:25:160: error: unknown type name 'UITableView'
static NSInteger (*_logos_orig$_ungrouped$WCTableViewManager$numberOfSectionsInTableView$)(_LOGOS_SELF_TYPE_NORMAL WCTableViewManager* _LOGOS_SELF_CONST, SEL, UITableView *); static NSInteger _logos_method$_un...
4.导入了 <UIKit/UIKit.h>
编译失败:
==> Notice: Build may be slow as Theos isn’t using all available CPU cores on this computer. Consider upgrading GNU Make: https://github.com/theos/theos/wiki/Parallel-Building
> Making all for tweak WechatTweak…
==> Preprocessing Tweak.x…
==> Compiling Tweak.x (armv7)…
==> Linking tweak WechatTweak (armv7)…
ld: warning: building for iOS, but linking in .tbd file (/opt/theos/vendor/lib/CydiaSubstrate.framework/CydiaSubstrate.tbd) built for iOS Simulator
Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_UIAlertController", referenced from:
objc-class-ref in Tweak.x.ae33fabd.o
"_OBJC_CLASS_$_UIApplication", referenced from:
objc-class-ref in Tweak.x.ae33fabd.o
"_OBJC_CLASS_$_UITableViewCell", referenced from:
objc-class-ref in Tweak.x.ae33fabd.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
需要在 Makefile
文件中,指定要导入的 Framework
:
TARGET := iphone:clang:latest:10.0
INSTALL_TARGET_PROCESSES = SpringBoard
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = WechatTweak
WechatTweak_FILES = Tweak.x
WechatTweak_CFLAGS = -fobjc-arc
WechatTweak_FRAMEWORKS = UIKit
include $(THEOS_MAKE_PATH)/tweak.mk