在越狱环境下,如果我们需要为插件添加配置项,第一个想到的就是大名鼎鼎的 ,这个插件可以在 iOS 设置中添加一个 ,在里面加上我们插件的配置。但是如果我们想在目标应用中直接添加配置界面,或者想在未越狱设备上添加配置界面,这个时候就面临着要编写一整套配置 UI 的窘境。如果配置项比较多,这个配置界面的编写也算是挺麻烦的。

×2208 183 KB
为了在这种情况下依旧能够享受类似 功能的便利,我编写了 XUI,这是一个能够依据配置文件,创建出基于 的配置界面。XUI 的使用相比 而言更加简便,而且更加强大。
XUI 开源于 :
XUI 技术文档:Home · /XUI Wiki ·
注:因为 XUI 是为我的另一款产品 设计的,所以配置文档中要求使用 Lua 创建配置,但是实际使用中你需要使用 json 或 plist 字典创建配置,语法上大同小异。
开始
首先我们在已越狱的测试机上安装最新版本的QQ(本文使用的版本是 v7.5.0.407)。
安装 ,安装及配置步骤参见: – /: Tweak、Logos Tweak and -line Tool、Patch iOS Apps, .
注意,这里我们配置了测试机 SSH 的免密登录,并在设备上安装了 frida。
配置完成后,我们创建一个新的 ,取名为 ,注意 App 填写 “QQ”,这样 会自动使用 frida 砸壳并导出 ipa。

-8BF4-4A36-86A4-×1052 52.6 KB
第一次运行需要耐心等待砸壳过程,这时应用会启动,如果构建成功,接下来我们为插件添加 XUI 配置界面。在工程目录下创建 ,然后运行 pod :
use_frameworks!
target 'QQRecallPatchDylib' do
pod 'XUI', :git => "https://github.com/Lessica/XUI.git"
end

-A2E5-4F12-967D-×960 51.2 KB
关闭 ,打开工程目录中出现的 ,可以看到 XUI 库已经被引入。接下来我们创建一个 XUI 界面配置 目录 .,内含一个 XUI 界面文件 .json,将其添加到 项目的资源中:
{
"title":"插件配置",
"theme":{
"navigationTitleColor": "#000000",
"navigationBarColor": "#FFFFFF"
},
"items":[
{
"label":"功能",
"cell":"Group",
"footerText":"Author: i_82 "
},
{
"cell":"Switch",
"label":"开启防撤回",
"key":"RecallPatchEnabled",
"default":true
}
]
}
注意图中红框部分,组件 代表一个开关,其 key 我们设置为 ,之后我们获取配置的时候要用到。

-70C6-4040-8F8B-×1414 439 KB
确保这个 资源被正确引入到工程中:

-89A4-4360-8046-×1414 429 KB
在目标应用中,为插件的 XUI 配置界面添加入口按钮,这里我们在 设置界面的导航栏右上角添加一个按钮入口:
%hook QQSettingsViewController
- (void)viewDidLoad {
%orig;
UIBarButtonItem *tweakItem = [[UIBarButtonItem alloc] initWithTitle:@"插件" style:UIBarButtonItemStylePlain target:self action:@selector(tweakItemTapped:)];
[tweakItem setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]} forState:UIControlStateNormal];
self.navigationItem.rightBarButtonItem = tweakItem; // 在 QQ 设置界面导航栏右上角添加按钮
}
%new
- (void)tweakItemTapped:(id)sender {
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"QQRecallPatch" ofType:@"bundle"];
NSString *xuiPath = [[NSBundle bundleWithPath:bundlePath] pathForResource:@"interface" ofType:@"json"];
[XUIListViewController presentFromTopViewControllerWithPath:xuiPath withBundlePath:bundlePath]; // 从顶层 UIViewController 将 XUI 配置界面 present 出来
}
%end
最后一歩,实现防撤回插件的主要功能,这里我就不多说了,各位按照自己插件的功能自由发挥。需要获取配置的时候,只需要从 [ ] 中读取即可,这里我们就可以读取刚刚的配置项 ,例如:
id enabledVal = [[NSUserDefaults standardUserDefaults] objectForKey:@"RecallPatchEnabled"];
if (!enabledVal) {
enabledVal = @(YES); // default value
}

-FD1A-41FF-8B0D-×1414 527 KB
接下来我们看看效果:

×2208 163 KB

×2208 83.3 KB
对于 XUI 的介绍大致就是这样,更多丰富的组件大家可以在 XUI 文档中找到:Home · /XUI Wiki ·
强烈安利庆哥的 ,用它做越狱插件开发简直不能再赞。
示例工程(不包含 App):