Cycript是由Cydia创始人Saurik推出的一款脚本语言,Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用Oc或者JavaScript,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改很多东西。
安装
从官网上下载SDK到本地,并配置到本地shell中以便全局使用。每个人配置用的shell不一样,一般都是使用bash,我使用是的zsh,就不举步骤了;安装成功标志
$ cycript
cy#
简单使用
lldb需要把程序停下来才能调试,而cycript可以动态的调试;上面已经的步骤已经把cycrip插件安装到了本地电脑上了,那么如何把cycript插件安装到手机呢?
- 1.如果是越狱手机,那么可以直接在越狱手机中安装cycript插件
- 2.如果没有越狱手机,那么可以使用MonkeyApp重签微信的ipa包
我这里选择的是第二种。
连接
- 1.查看Monkey连接端口,当然这端口可以自定义。
- 2.将你的电脑和手机连上同一个局域网,查看当前网络ip地址
- 3.将电脑和手机连接上,10.89.3.114 是ip地址,是端口号
$ cycript -r 10.89.3.114:6666
//有cy#这个符号出现就代表连接成功了,就可以愉快调试了
cy#
退出cycript调试 control + d;
如果遇到这个错误:*** _syscall(connect(socket_, info->ai_addr, info->ai_addrlen)):../Console.cpp(306):CYSocketRemote [errno=60],换一个wifi试试、换个手机(换ip)。还是不行的话就用手机给电脑开热点。就是ip或端口或Wi-Fi的问题。
注意:在调试的时候不要将app退到后台,会导致cycript连接失败
Cycript 常用命令
使用例子
//获取keyWindow()
cy# UIWindow.keyWindow()
#"<iConsoleWindow: 0x10aa4e090; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x281719860>; layer = <UIWindowLayer: 0x2818b0680>>"
cy# [UIApplication sharedApplication]
#"<UIApplication: 0x10aa17610>"
//内置的cy命令
cy# UIApp
#"<UIApplication: 0x10aa17610>"
//自定义变量
cy# var keyWd = UIWindow.keyWindow()
#"<iConsoleWindow: 0x10aa4e090; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x281719860>; layer = <UIWindowLayer: 0x2818b0680>>"
cy# keyWd.rootViewController
#"<MMUINavigationController: 0x10b108600>"
//# 指针打印
cy# #0x10b108600
#"<MMUINavigationController: 0x10b108600>"
//*打印对象变量属性
cy# *keyWd
{isa:iConsoleWindow,_hasOverrideClient:0,_hasOverrideHost:0,_hasInputAssistantItem:0,_constraintsExceptingSubviewAutoresizingConstraints:null,_cachedTraitCollection:null,_animationInfo:null,_layer:#"<UIWindowLayer: 0x2818b0680>",_layerRetained:#"<UIWindowLayer: 0x2818b0680>",_gestureRecognizers:@[#"<_UISystemGestureGateGestureRecognizer: 0x2827160d0; state = Possible; delaysTouchesEnded = NO; view = <iConsoleWindow 0x10aa4e090>>",#"<_UISystemGestureGateGestureRecognizer: 0x2827161c0; state = Possible; delaysTouchesBegan = YES; view = <iConsoleWindow 0x10aa4e090>>"],_window:null,_subviewCache:@[#"<UITransitionView: 0x10a916ab0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x28193b860>>"],_templateLayoutView:null,_pseudo_id:34,_viewDelegate:null,_backgroundColorSystemColorName:@"clearColor",_countOfMotionEffectsInSubtree:0,_unsatisfiableConstraintsLoggingSuspensionCount:0,_countOfTraitChangeRespondersInDirectSubtree:2,_cachedScreenScale:0,_viewFlags:@error,_layoutSubviewsCount:0,_imminentLayoutSubviewsCount:0,_retainCount:14,_draggingSourceDelegate
//choose() 获取视图中所有的某种类型的对象
cy# choose(UIButton)
[#"<UIButton: 0x10aa5bfb0; frame = (232 20; 88 49); opaque = NO; autoresize = LM; layer = <CALayer: 0x2818d1a20>>",#"<UIButton: 0x10aab7720; frame = (193 13; 19 19); opaque = NO; layer = <CALayer: 0x281972980>>",#"<UICalloutBarButton: 0x10aabb980; frame = (0 0; 30 34); hidden = YES; opaque = NO; layer = <CALayer: 0x281971a20>>",#"<FixTitleColorButton: 0x10a918940; baseClass = UIButton; frame = (20 76; 280 47); clipsToBounds = YES; opaque = NO; autoresize = W; layer = <CALayer: 0x281956820>>",#"<MMBarButton: 0x10a92e120; baseClass = UIButton; frame = (0 0; 40 44); opaque = NO; autoresize = H; layer = <CALayer: 0x281956a80>>",#"<UIButton: 0x10a92e460; frame = (0 0; 58 19); opaque = NO; layer = <CALayer: 0x2819572e0>>",#"<UIButton: 0x10a92f880; frame = (73 0; 58 19); opaque = NO; layer = <CALayer: 0x2819574e0>>",#"<FixTitleColorButton: 0x10a93e9f0; baseClass = UIButton; frame = (20 15; 130 47); clipsToBounds = YES; opaque = NO;
打印视图层级
//recursiveDescription().toString()打印视图层级
cy# keyWd.recursiveDescription().toString()
`<iConsoleWindow: 0x10aa4e090; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x281719860>; layer = <UIWindowLayer: 0x2818b0680>>
| <UITransitionView: 0x10a916ab0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x28193b860>>
| | <UILayoutContainerView: 0x10a944110; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x2817dee20>; layer = <CALayer: 0x281935ba0>>
| | | <UINavigationTransitionView: 0x10a97d8d0; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x281936100>>
| | | | <UIViewControllerWrapperView: 0x10aa50cb0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x281953920>>
| | | | | <UIView: 0x10aa33260; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x281925260>>
...
打印视图层级这个方法可以用于查找特定视图
脚本自动连接
在上面的演示中我们每次连接都要输入$ cycript -r 10.89.3.114:6666,其实我们可以用脚本自动连接;
- 1.找一个不太被修改的位置,新建脚本文件夹和cy脚本文件
$ cd /Users/xxx
//新建脚本文件夹
$ mkdir RFShell
//新建cy脚本文件并编辑
$ vim cyLogin.sh
- 2.给脚本文件添加执行权限
chmod 777 cyLogin.sh
- 3.全局配置脚本
vi ~/.zshrc
- 4.测试
$ sh cyLogin.sh
cy#
cycript 练习
//连接cycript
sh cyLogin.sh
cy# UIApp
#"<UIApplication: 0x12fe15150>"
cy# [UIApp setStatusBarHidden:YES]
cy# [UIApp setStatusBarHidden:NO]
cy# [UIApp setApplicationIconBageNumber:998]
复杂数据修改
查找对象
cy# choose(UITableViewLabel)
#"<UITableViewLabel: 0x12fe95a10; frame = (224.5 8; 65.5 27.5); text = '+1876'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2820a3e80>>"
修改对象
cy# #0x12fe95a10.text = "博特尔"
cycript高级用法
cy文件
- cycript是一门脚本语言,它可以加载封装好的.cy文件
- 将常见的Cycript功能封装到.cy文件,就可以很方便的调用 MonkeyDev本身集成了几个网络上的.cy文件,所以我们可以调用
使用例子
- APPID
cy# APPID
@"riceFun.KTest"
- pactions 打印对象action
cy# pactions(#0x131216a30)
"<WCAccountMainLoginViewController: 0x13001ea00> onSwitch"
- rp 响应链
cy# rp(#0x131216a30)
`<UIButton: 0x131216a30; frame = (20 18; 181 22); opaque = NO; autoresize = LM; layer = <CALayer: 0x2802e5360>>
<UIView: 0x12fe53d60; frame = (0 0; 320 123); autoresize = LM+RM; layer = <CALayer: 0x2802e4040>>
<UIView: 0x12fe59750; frame = (0 181; 320 123); layer = <CALayer: 0x2802e5e20>>
<WCTableView: 0x130192800; baseClass = UITableView; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x280ceb9f0>; layer = <CALayer: 0x280245dc0>; contentOffset: {0, -64}; contentSize: {320, 304}; adjustedContentInset: {64, 0, 0, 0}>
<UIView: 0x12feaa6f0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x280244200>>
<WCAccountMainLoginViewController: 0x13001ea00>
<UIViewControllerWrapperView: 0x12fd79c90; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x2802e1960>>
<UINavigationTransitionView: 0x12fd5de90; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x28029d500>>
<UILayoutContainerView: 0x12fd7b900; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x280c99470>; layer = <CALayer: 0x280293aa0>>
<MMUINavigationController: 0x13087ac00>
<MMUINavigationController: 0x1308d5800>
<UITransitionView: 0x12fdd61b0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x2802e1820>>
<iConsoleWindow: 0x12fd4de20; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x280cd6970>; layer = <UIWindowLayer: 0x28036ef20>>
<UIApplication: 0x12fe15150>
<MicroMessengerAppDelegate: 0x283fdf100>`
自己封装.cy文件
-
新建.cy文件 Xcode - File - New - Empty文件
-
copy File 到工程中
-
编辑.cy文件
下面是我的cy文件的内容,便于大家参考
//IIFE 匿名函数自执行表达式
(function(exports){
K_APPID = [NSBundle mainBundle].bundleIdentifier,
K_APPPATH = [NSBundle mainBundle].bundlePath,
//如果有变化,就用function去定义!!
K_Rootvc = function(){
return UIApp.keyWindow.rootViewController;
};
K_KeyWindow = function(){
return UIApp.keyWindow;
};
K_GetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = K_GetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = K_GetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
K_CurrentVC = function(){
return K_GetCurrentVCFromRootVc(K_Rootvc());
};
})(exports);
- 使用
使用之前要重新跑下程序
//记得自定义的一定要@import
cy# @import appConvince
{}
cy# K_APPID
@"riceFun.KTest"
cy# K_APPPATH
@"/var/containers/Bundle/Application/DC9FADE7-6224-46AB-B596-F2CF127C4BBC/KTest.app"