一个实用的悬浮球工具

2017/03/10 iOS

前言

已经很久没有写文章了,前面写过一篇 关于 UIWindow 的文章,在文章的最后提过悬浮球。用 UIWindow 来做悬浮球,可以悬浮在任意页面,基于这个特性,我将其做成了一个工具,用在我们的项目开发中,今天把它作为主角来讲一讲。

先上代码 → ZYSuspensionView GitHub 传送门

为什么会有它

想要指定执行一些代码

在做公司项目的时候,可能会有这样的情况,我需要在第一个进某个页面的时候弹出一些东西,简单做法,可能就会再、在 NSUserDefaults 中记录一个值,表明弹出过。可能我第一次弹出之后又一些问题,我改了代码,运行工程,重新进页面让它弹出,可是却弹不出来了,因为已经标记为弹出过,把包删了,重运行工程即可。

testmanager.gif

不过有了悬浮球,我通过点击悬浮球,弹出一个列表,列表中每个 cell 对应我预先写好的一些常用代码,例如清除 NSUserDefaults 所有键值对等等,然后就达到了想要的效果。当然这个比喻有很多槽点,不过就这样吧,不纠结。

真实用例如下,希望对你有点启发:

  1. 通过手动插入一条的指定体重体脂率的体重数据

    我们公司做体脂秤,所以开发的时候经常需要这么做,不然就得光着脚在秤上称,还不一定是自己想要的数值

  2. 清除 NSUserDefaults,让包里的标记干净得像初恋一样
  3. 显示 log

    有时候测试人员测试的时候,发现页面的 bug,可能我们在有些 case 预留了一些 log,但是想要导出就麻烦一些,通过点悬浮球列表的某个 cell 跳转到一个显示 log 的页面,快捷方便

  4. 显示当前账号的 user id 及其他信息

    我们需要经常查当前账号信息

  5. 跳转到指定页面

    正在开发某个页面,需要依赖工程里的东西,所以在工程里开发,但是还没有开发完,由于入口深,每次改了一些东西重新跑工程还得点几下,麻烦。修改 app 首页的某个按钮点击事件,直接点击进入也不合适,影响正式代码,而且容易忘记改回来。

  6. 其他一些杂七杂八的…

不想每次都输入账号密码

因为项目的原因,很多功能展示都和当前账号的数据有关系,所以想要自测自己的功能是否 OK,就需要频繁切换账号,以保证每种情况都是真实 cover 到了。

loginmanager.gif

用悬浮球,弹出一个账号菜单,点击自己想要登陆的账号,直接自动登陆,妈妈再也不用担心我每天都要输入几百次密码了。 🤣

好用吗?怎么用?

个人感觉还是很好用了,为自己开发省去了不少时间,同时也为测试同学省去不少麻烦(有点自卖自夸的性质了哈 😠)。页面简单朴素,就是悬浮球 + 一个列表,咱不整那些虚的,主要就是实用。好不好用,试试就知道了。

我已经将这个悬浮球做成了一个 Pod 库,公司的项目用了近一年了,稳定,暂未发现有什么问题,如有 bug 可以给我提 issue。

这个组件主要分为个部分

  • SuspensionView
  • TestManager
  • LoginManager

SuspensionView 就是单纯一个悬浮球,可以单独集成。

TestManager

TestManager 是一个单例,将你预先写好的代码块保存好,然后通过点击悬浮列表的某个 cell 执行相应代码块。

使用的时候,一般分为两个部分:

一些是常驻的一些测试代码,例如展示 log,清除 user defaults 等…

NSArray *baseArray = @[
                       @{
                           kTestTitleKey: @"clean user defaults",
                           kTestAutoCloseKey: @YES,
                           kTestActionKey: ^{
                               NSLog(@"click 'clean user defaults'");
                               [self cleanUserDefaults];
                           }
                           },
                       @{
                           kTestTitleKey:@"something",
                           kTestAutoCloseKey: @NO,
                           kTestActionKey:^{
                               NSLog(@"click 'something'");
                           }
                           },
                       ];
    
[ZYTestManager setupPermanentTestItemArray:baseArray];
  • kTestTitleKey 是测试条目的名字
  • kTestAutoCloseKey 为点击该条目之后是否自动关闭悬浮列表
  • kTestActionKey 很显然,这就是点击之后想要执行的代码

当然,一些不常用的测试代码,可能就是你突发奇想要跳转到某个页面,但是不影响项目的其他功能正常运行,就可以使用另一个方法

[ZYTestManager addTestItemWithTitle:@"new item" autoClose:YES action:^{
    // click new item : do something ~~~~~~~~~~
}];

这里需要说明一些,传入 block 的时候,如果用到 self,最好使用 __weak,避免影响到你正常功能,毕竟 TestManager 是一个单例。

LoginManager

LoginManager 顾名思义,就是拿来做自动登录的,同样,点击 login 悬浮球,弹出账号列表,再点击对于 cell,LoginManager 会回调给你储存好的这个账号的账号和密码。

- (void)loginManager:(ZYLoginManager *)loginManager loginWithAccout:(NSString *)account password:(NSString *)password
{
	// 这里去实现你的自动登录
}

可能你会说,自动登录都是我实现了,拿你还有什么用呢。LoginManager 做了如下事情:

  • 帮你存储账号密码
  • 列表展示你预先设置或者登录过的账号,并通过你的点击回调给你

自动登录的代码是不可能帮你做好的,因为每个工程里的与登录对于的代码完全不同,不可能通用,所以,咱只能做到这一步了,哈哈哈。不过这里还是给你提供了一个获取当前控制器的方法,可以直接使用

UIViewController *currentVC = [ZYLoginManager currentViewControllerWithWindow:nil];

其实自动登录无非就是两步

  1. 获取当前控制器,查看是否为登录的控制器
  2. 如果是,利用 performSelector 调用登录部分的代码

如果不是登录的控制器怎么办呢?一般的 app,在没有登录的时候一般第一个页面就是登录页面,或者点击一下某个按钮,跳转到登录页面,其实获取当前控制器的时候,完全可以判断是否为第一个页面,如果是,就 performSelector 跳转到登录页面,再在登录页面 performSelector 调用登录部分的代码。根据不同情况再做一些调整吧。

除了是实现这个方法,你还需要做两件事情:

  • 告诉我你登录成功了,并且告诉我是哪个账号,我这时候需要隐藏登录的悬浮球,并且为你保存账号
[[NSNotificationCenter defaultCenter] postNotificationName:@"kZYLoginSuccessNotificationKey"
                                                    object:@{account:password}];
  • 告诉我你退出登录了,我需要重新展示登录按钮,方便下一次自动登录
[[NSNotificationCenter defaultCenter] postNotificationName:@"kZYLogoutSuccessNotificationKey"
                                                    object:nil];

安全吗?

这东西,能跟着上线吗,不小心蹦出来个悬浮球给用户看到那不是尴尬了。不能携带上线的话,每次上线还得删除,多麻烦啊。😎 这个大可放心,我已经带着它上线了 n 个版本了,而且几乎所有代码我都加上了

#if DEBUG
...
#endif

所以根本不需要担心,只要工程改为 release 模式运行压根就出现不了悬浮球,里面的代码根本也不会执行。

我的建议是像我 demo 里面那样,写一个 config 类,将上面所有常用的测试代码和测试账号都写在这里类里面,放在一起,将污染做到最小。如果你这样做了,在这里 config 类的 setup 方法再加上一个 #if DEBUG,你会发现 TestManagerLoginManager 这两个单例对象根本就不会初始化,还有什么可担心的。

基本就这么多吧,如果你觉得有用的话,请不要吝啬你的 star🌹 哦!

Search

    Table of Contents