修复 macOS 应用去除签名后的沙盒路径

自从做了两个Tweak:WeChatTweak-macOS 和 QQTweak-macOS,发现了都存在一个共同问题:由于以上两个应用都采用了 macOS 的沙盒机制,同时插入动态库时签名被移除,导致了沙盒失效,拖延症的我终于在国庆期间修复,并记录一下过程。 0x00 举个例子 以下应用在安装完 Tweak 之后,会导致沙盒失效,因此会导致聊天记录等文件无法加载,同时文件路径会出现错乱。囧rz…… WeChat 无法加载历史聊天记录等 ~/Documents 目录下出现 MMappedKV 文件夹。参考 #19 ~/Documents 目录下出现 JietuSDKStat.plist。

让微信 macOS 客户端支持 Alfred

Alfred 作为 macOS 平台上的效率神器,Dash、Evernote等应用配合 Alfred 能够有很好的效率提升与体验,然而还是有很多应用未能支持得,比如 Telegram、微信等经常使用的一些应用。既然原生未能支持,那么自己来动手搞一个了~ 0x00 相关回顾 GitHub: WeChatTweak-macOS 微信 macOS 客户端无限多开功能实践 微信 macOS 客户端拦截撤回功能实践 以上为微信 Tweak 增强的以往的一些文章资料,可供参考。 0x01 需求 通过 Alfred 模糊搜索联系人并快速跳转到对应聊天界面

微信 macOS 客户端无限多开功能实践

继上一次的 微信 macOS 客户端拦截撤回功能实践 之后,有热心网友给我提了个 issue :macOS微信客户端的多开问题,才发现原来在 macOS 上微信客户端是不能多开的,于是接受挑战~ 0x00 传统多开方法 在 macOS 平台上,大部分应用都是支持多开的,比如: ⌘ + N 大法:适用于 QQ open -n /Applications/xxx.app 大法:适用于大部分的应用 那么对于微信客户端来说,以上两种方法都是无效的。其中第一种只能新建新的聊天对象)

从 Farbox 到 Bitcron

2014 入手的第一个域名,第一个基于 Wordpress 的个人 Blog 。只有三年时间,不算长,虽然写的是「 从Farbox到Bitcron 」,但更多的是折腾历史。 折腾 第一次用 Wordpress,没有服务器性能概念,也不 Care 访问速度,更不知道 HTTPS 等优化知识,只知道安装配置简单,主题华丽,于是买的廉价 PHP 服务器搭建一个 Wordpress,就这么折腾了一段时间…… Jekyll ,是在 GitHub 中发现的一个静态 Blog

实现 macOS 锁屏的两种方式

逛了一圈发现所有的远程锁定 App 都是基于蓝牙的,因此会有距离的问题=。=,并且蓝牙需要进行配对操作......于是自己写了个基于局域网 Socket 的远程锁定 LockMyMac ,再也不用担心想起忘记锁电脑却已走太远的情况了。 CGSession 大部分应用采用的方式,锁定时会有一个 3D 翻转的效果。 缺点:解锁只能使用密码登录,无法通过 Apple watch 自动登录 - (void)lockScreen { NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@"/System/

微信 macOS 客户端拦截撤回功能实践

微信的小贱人特多,尤其是群里的,老喜欢撤回,还有一大堆的跟风党起哄党...当然少不了一些手抖发错的,嘿嘿嘿。好奇心如此强的我怎能错过这些消息! 一、原理 要拦截撤回的消息,首先就要知道当客户端接收到撤回消息的通知时候,执行一个方法来撤回消息: 服务端 ---发送撤回通知---> 客户端接收 ---> 执行撤回消息的方法(删除本地消息,刷新UI,提示消息被撤回) 所以我们需要做修改的这个入口就是执行撤回消息的这个方法,让其不删除本地的消息就可以了。 二、准备 在OS X环境下逆向工具有以下几个大杀器: Hopper Disassembler - 反编译工具,能够将二进制执行文件反编译出伪代码

A hexo theme NexT for Farbox

此无人访问的Blog不知不觉已经两年了,期间折腾过不少,到最后发现Blog还是简单省心才是最好的,毕竟没人看。 关于NexT NexT,一个Hexo的漂亮并且简洁的主题。但是Hexo的操作太繁琐了,懒癌晚期的我连打字都懒,更别说Hexo中的各种操作命令。于是Farbox是我的最佳选择,但是太小众,主题模板除了官方提供的几个,第三方的屈指可数。 关于移植 关于移植,其实从很早很早以前就有这个打算了,每当我雄心勃勃地把NexT的源码Clone下来打开以后,表情大概如下图... 终于在前几天,狠下心一口气完成了... Github: Farbox-NexT NexT目录结构分析 ├── languages ├── layout │ ├── _components │ │ └── algolia-search │ ├── _macro │ ├── _partials │ │ ├── head │ │ ├── search │ │ └── share

Pokemon Go Hook 解锁地区实践

据说这游戏挺火的,但中国锁区,于是自己动手,但也踩了一些坑 准备 Clone项目:PokemonHook 解压PokemonHook的项目中的pokemon_unsigned.zip文件,获得Payload文件夹一个 Clone项目:iResign 直接获得iResignApp一个 登录Apple Developer Center下载XC Ad HocProvision Profile,用WildCard的就可以了 PS:如果用指定App ID的Profile,重签名步骤需要修改Info.plist文件 覆盖embedded.mobileprovision 这步没什么好说的= =|||,直接把从Apple Developer Center下载下来的moblieprovision重命名并覆盖到pokemongo.app

Tips: 查找项目中所有的中文字符串

如果项目中没有使用到国际化方案来处理一些文案字符串,而是直接 HardCode 到项目中的话(这是一个不好的习惯),到时候文案修改或者文案复用就会比较蛋疼,尤其是项目逐渐变大,很容易出现疏漏,因此为了避免各种文案字符串散落到项目各个地方,趁早改用国际化方案来处理。 例如 self.title = @"消息"; self.name = @"客服"; 查找项目中所有的中文字符串 打开Find Navigator 切换搜索模式至Regular Expression 输入@"[^"]*[\u4E00-\u9FA5]+[^"\n]

UITableView 实现平滑下拉加载历史记录

记录在项目中遇到的一个坑,在IM聊天的页面中需要一个下拉加载历史聊天记录的控件。 传统下拉刷新控件 本以为用MJRefresh就好了,但是却有以下一个致命的问题:下拉加载更多内容会强制跳动到TableView的顶部。然而网上找到的只是比较应付式的解决办法,效果并不好。 平滑下拉加载刷新控件 解决思路 解决办法其实也不复杂,清楚TableView加载前后的流程就可以了,当数据增多后执行[UITableView reloadData]方法后TableView改变的有: ContentSize,ContentSize会被里面的Cell撑开。 ContentOffset会变成{0, 0}。 因此我们要记录刷新前后的ContentSize,便可计算出需要停留的ContentOffset,那就可以实现平滑下拉加载的刷新控件了。 注意事项 不要忘了TableView的ContentInset咯。 具体实现 #import <UIKit/UIKit.h>

Realm 的线程问题

人人都说Realm好,逼格又够高,于是我也试试水,后来发现......线程是个坑,一不小心就进去了。 线程 每个程序都会至少有一个线程,如果只有一个线程,那么这个线程就是程序自己本身。 线程有三种状态分别是:就绪、阻塞、运行。 在一个进程包括多个线程 Realm中的线程问题 单线程 在单线程中,随便怎么玩都可以,只要注意把修改操作写到事务中。 多线程 对于还没有保存到数据库的RLMObject,其表现是和普通的NSObject没什么卵区别的,都是不用注意任何线程相关的问题。 但是对于RLMObject、RMLResults、RMLArray、RMLRealm已保存到数据库的实例只能够在其被创建的线程上使用,否则就GG。 跨线程操作实例 既然在多线程中,RLMXXX对象只能在其创建的线程中操作,又如何在别的线程操作呢?

关于 StatusBar 与 NavigationBar 适配的一些坑

最近在项目中遇到这样一个坑:项目中NavigationController之下的ViewControllers的NavigationBar有不同的样式(纯色Translucent,完全透明、隐藏等样式)。由于NavigationBar的颜色不同,StatusBar的颜色也必须随着其颜色深浅来作出适配。 适配StatusBar - (UIStatusBarStyle)preferredStatusBarStyle方法的半残废,在NavigationController下的ViewControllers直接使用该方法是不会执行的,因为NavigationController的特殊性,同时在查阅Apple官方文档可以重写childViewControllerForStatusBarStyle这个方法: 但是太麻烦了,并没有什么卵用。 所以,我们可以一劳永逸,写一个UINavigationController的Category来扩展此方法: #import <UIKit/UIKit.h> @interface UINavigationController (GBExtension) - (UIViewController *)childViewControllerForStatusBarStyle; - (UIViewController

Xcode Auto-Increment Build Number

介绍 在Xcode项目中存在这两个版本号,分别是Bundle version和Bundle versions string, short,都是在Info.plist文件中。 区别 Bundle version:这个一般是开发这需要关注的,因为这个代表每一次打包发布的版本号码,对于持续化集成维护方面能够准确定位到哪个版本出问题。 Bundle versions string, shotr:这个是给用户关注的版本号,通常正式发布一个上线版本才会修改这个版本号,以表示升级,用户通过该版本号向开发者反馈问题。 配置 if [ $CONFIGURATION == Release ]; then echo "Bumping build number.

Swift 中的 ? 与 !

在Swift中多出了这两个玩意?和!,到底是什么鬼?! 用法 在声明变量的时候会用到: var sunny: String? var young: String! 在调用变量进行使用操作会用到: sunny?.isEmpty young!.isEmpty //其实这里可以这样写young.isEmpty 普通情况下,在声明一个变量的时候如果不手动初始化,则不会自动给该变量一个初始的默认值: var sunny: String //没有任何值 println(sunny) //报错 对于在类型后面加了?的变量为Optional变量,如果不给定初始值,则系统会自动给它一个默认初始值为nil。 对于在类型后面加了!

把 Delegate 封装成 Block

UIAlertView和UIActionSheet之类的控件只支持Delegate方式作为回调,但是这样小的操作要把代码分散开来就很不爽了~因此有了**BlocksKit**这个第三方开源扩展库,但是如果要自己封装一个的话也未免不可~主要是用到了关联来扩展了它们的属性。 直接来个UIAlertView做个例子 #import <UIKit/UIKit.h> #import <objc/runtime.h> typedef void(^CompletionBlock) (NSInteger buttonIndex); @interface UIAlertView (Block) - (void)showAlertViewWithCompletion:(CompletionBlock)completion;

iOS DevCenter 中各个证书的说明

iOS DevCenter到底是什么鬼,个人觉得界面不清晰(虽然已经比以前好了)但是各个证书的关系比较难理解,再加上新版的Xcode集成了部分管理证书的功能,但是!缺偏偏只做了一半,部分功能还是得上网页上去管理,像我这种懒人肯定懒得看官方的全英文档来理解,不过这种东西,还是这句话:“用得多就自然懂了”。 Certificates 证书主要分为两类:Development和Production,Development证书用来开发和调试应用程序,Production主要用来分发应用程序。 同时要注意的一点就是申请完证书时,最好导出并保存好你的私钥。 Identifiers App ID用于标识一个或者一组App,App ID应该是和Xcode中的Bundle ID是一致的。 Explicit App ID:唯一的App ID,这种App ID用于唯一标识一个应用程序。

Category 添加 property

一开始Google了解到在iOS开发中的Category是不可以添加property的,via:StackOverFlow,其实当时我是信的,但是后来发现在别的开源代码中readonly属性的property能够在运行时给它们赋值操作,借助于Objective-C Runtime中的关联,所谓关联是指把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分。 两个主要方法 id objc_getAssociatedObject ( id object, const void *key ); void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy ); 使用方法 -

GitHub Pages 与 GitCafe Pages的比较

2015-03-27 GitHub又被搞了,于是GitHub Pages就一直半死不活,于是就趁机尝试了下GitCafe的Pages服务 转移 在GitCafe中创建一个跟自己用户名相同的仓库 创建名为gitcafe-pages的分支 把GitHub的仓库直接Clone到刚刚创建的gitcafe-pages分支 Done! 具体详情步骤可以参看GitCafe官方Wiki: https://gitcafe.com/GitCafe/Help/wiki/Pages 域名绑定 A 记录到 207.226.141.135 CNAME 记录到 * 在Pages服务中添加自己的域名和二级域名 比较 速度 这个不用多说了,目前情况GitCafe是比GitHub快的 域名绑定