XUI:为 MonkeyDev 插件添加配置界面


#1

XUI:为 MonkeyDev 插件添加配置界面

前言

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

为了在这种情况下依旧能够享受类似 PreferencesLoader 功能的便利,我编写了 XUI,这是一个能够依据配置文件,创建出基于 UITableView 的配置界面。XUI 的使用相比 PreferencesLoader 而言更加简便,而且更加强大。

  • 支持创建子界面
  • 支持数十种配置组件
  • 支持自定义主题颜色
  • 支持 Bundle 与资源引用、多语言等特性

XUI 开源于 Github: https://github.com/Lessica/XUI
XUI 技术文档:https://github.com/Lessica/XUI/wiki

注:因为 XUI 是为我的另一款产品 XXTouch 设计的,所以配置文档中要求使用 Lua 创建配置,但是实际使用中你需要使用 json 或 plist 字典创建配置,语法上大同小异。

开始

首先我们在已越狱的测试机上安装最新版本的QQ(本文使用的版本是 v7.5.0.407)。

安装 MonkeyDev,安装及配置步骤参见:https://github.com/AloneMonkey/MonkeyDev
注意,这里我们配置了测试机 SSH 的免密登录,并在设备上安装了 frida。

配置完成后,我们创建一个新的 MonkeyApp,取名为 QQRecallPatch,注意 Target App 填写 “QQ”,这样 MonkeyDev 会自动使用 frida 砸壳并导出 ipa。

第一次运行需要耐心等待砸壳过程,这时应用会启动,如果构建成功,接下来我们为插件添加 XUI 配置界面。在工程目录下创建 Podfile,然后运行 pod install

use_frameworks!

target 'QQRecallPatchDylib' do
     pod 'XUI', :git => "https://github.com/Lessica/XUI.git"
end

关闭 xcodeproj,打开工程目录中出现的 xcworkspace,可以看到 XUI 库已经被引入。接下来我们创建一个 XUI 界面配置 Bundle 目录 QQRecallPatch.bundle,内含一个 XUI 界面文件 interface.json,将其添加到 QQRecallPatch 项目的资源中:

{
    "title":"插件配置",
    "theme":{
        "navigationTitleColor": "#000000",
        "navigationBarColor": "#FFFFFF"
    },
    "items":[
        {
            "label":"功能",
            "cell":"Group",
            "footerText":"Author: i_82 <i.82@me.com>"
        },
        {
            "cell":"Switch",
            "label":"开启防撤回",
            "key":"RecallPatchEnabled",
            "default":true
        }
    ]
}

注意图中红框部分,组件 Switch 代表一个开关,其 key 我们设置为 RecallPatchEnabled,之后我们获取配置的时候要用到。

确保这个 Bundle 资源被正确引入到工程中:

在目标应用中,为插件的 XUI 配置界面添加入口按钮,这里我们在 QQ 设置界面的导航栏右上角添加一个按钮入口:

%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

最后一歩,实现防撤回插件的主要功能,这里我就不多说了,各位按照自己插件的功能自由发挥。需要获取配置的时候,只需要从 [NSUserDefaults standardUserDefaults] 中读取即可,这里我们就可以读取刚刚的配置项 RecallPatchEnabled,例如:

id enabledVal = [[NSUserDefaults standardUserDefaults] objectForKey:@"RecallPatchEnabled"];
if (!enabledVal) {
    enabledVal = @(YES); // default value
}

接下来我们看看效果:



对于 XUI 的介绍大致就是这样,更多丰富的组件大家可以在 XUI 文档中找到:https://github.com/Lessica/XUI/wiki

强烈安利庆哥的 MonkeyDev,用它做越狱插件开发简直不能再赞。

示例工程(不包含 Target App):https://github.com/Lessica/QQRecallPatch


#2

膜吴总:rofl:


#3

XXT广告,实锤了


#4

膜XXT、膜XUI


#5

给吴总双击 666


#6

先有吴总后又天,吴总赛过活神仙


#7

来人 把我珍藏的意大利面端出来给吴总尝一尝


#8

这个标题的表意貌似不是太清晰,我的理解是,文章介绍了

用MonkeyDev开发tweak时,可以用XUI,摆脱对PreferencesLoader的依赖,直接为目标App添加配置项

也就是说,XUI其实是针对MonkeyDev的一个插件(framework),集成了之后,可以方便地在tweak里为App添加配置项,是这个意思吗?

如果是的话,标题可以改为《在MonkeyDev上配合XUI开发tweak,轻松为目标App添加配置界面》,表意更清晰一些


#9

恰恰不是这个意思……

XUI 是一个 Cocoapods 仓库,既可以给正常 App 使用,也可以作为静态/动态库,链接到你的插件工程里去的,而不是作用于 MonkeyDev 的一个插件。

总而言之,那个配置界面是 XUI 根据 json 配置文件,运行时展现出来的而不是根据配置文件进行预处理生成一段 OC 代码,进行编译后产生的界面。


#10

那其实提不提MonkeyDev都可以了,就叫《用XUI为tweak方便地添加配置界面》反而更容易理解


#11

不提 MonkeyDev 就没啥事儿说了哈哈…… 毕竟都是正向内容


#12

:grinning: XXTouch 越来越完善了!


#13

:grinning: XXTouch 越来越完善了!


#14

:grinning: XXTouch 越来越完善了!


#15

:grinning: XXTouch 越来越完善了!


#16

:grinning: XXTouch 越来越完善了!