anos
(anos)
2017 年12 月 14 日 02:29
#1
CALayer有一个私有api doubleBounds, 想访问这个私有api返回的数据,用了下面的代码:
id valuedoubleBounds = [view.layer performSelector:NSSelectorFromString(@“doubleBounds”)];
结果发现崩了,提示-[CALayer doubleBounds]: unrecognized selector sent to instance
根据链接:CALayer.h
可以知道doubleBounds是下面这样定义的,返回一个结构体数据,并且查看历史记录知道从iOS7到iOS10这个方法是一直存在于CALayer里面的
(struct CADoubleRect { struct CADoublePoint { double x_1_1_1; double x_1_1_2; } x1; struct CADoubleSize { double x_2_1_1; double x_2_1_2; } x2; })doubleBounds;
我是在非越狱环境下调用这个私有api的,目前测试iOS10.3.3和iOS7越狱设备调用这个api都会崩,虽然调用这个私有api 不是必需,但很想知道为什么调用这个私有api就会出错
同样的环境下,调用UIView的私有api recursiveDescription就完全没问题
anos
(anos)
2017 年12 月 14 日 03:40
#3
anos:
doubleBounds
你再搜搜看,doubleBounds 这个方法因为返回的是一个结构体,所以方法名超长
anos
(anos)
2017 年12 月 14 日 07:37
#5
我用新建的Xcode工程试了你的代码都是会崩的,这真是要命
但是,但是我灵机一动,把这段代码复制到以前做的一个大型app中,居然就不崩了
我以为是没有引用头文件的问题,在新建Xcode工程里加上了#import <QuartzCore/QuartzCore.h>
还是会崩
猜测这个方法是category里面的,如果没有正确import对应的framework,所以就会必崩?
anos
(anos)
2017 年12 月 14 日 08:05
#6
还是没有定位出来要添加什么东东才能导致调用这个私有api不出错
从另一方面来说,这个私有api隐藏得很不错
分类的话,可能不是,因为根据上面的 CALayer.h
的头文件,方法是在
// Image: /System/Library/Frameworks/QuartzCore.framework/QuartzCore
下的,应该就在 QuartzCore
我运行时用 image list
打印加载的库会有如下的输出
Developer/Xcode/iOS DeviceSupport/11.0 (15A372)/Symbols/System/Library/Frameworks/QuartzCore.framework/QuartzCore
然后用 respondsToSelector
返回也是 1
如果是设备,系统 ,Xcode
版本都是一致的,我还是比较倾向于是工程配置的问题,可能比较 Build Settings
会有一些启发吧
anos
(anos)
2017 年12 月 14 日 10:13
#8
要说某个工程配置能隐藏私有api这么深倒是有点不相信啊,recursiveDescription也是私有api,怎么就用得好好的
是有点神奇, 怀疑是不是发错类了, 或者调用前打印下_shortMethodDescription
anos
(anos)
2017 年12 月 14 日 14:20
#10
没理由发错类的,因为崩的时候报的错都是 -[CALayer doubleBounds]: unrecognized selector sent to instance,说明类CALayer没有错吧
Zhang
2017 年12 月 15 日 00:45
#11
那天在庆哥群里就跟你说了在category里拿IMP看下实现在哪自己加载
anos
(anos)
2017 年12 月 15 日 07:19
#12
我知道可以通过 NSSelectorFromString 和 methodForSelector 拿到一个OC方法的IMP,可是怎么拿IMP看下实现在哪?这个实在不会啊,求教
anos:
doubleBounds
额… 不是说工程配置有专门隐藏私有API的东西,而是说你原来的工程既然可以,那是不是原来的工程是不是手动引入了一些 framework
,而那个里面有那个 doubleBounds
。
根据下面的那个截图, doubleBounds
应该是在 MapKit
而不是 QuartzCore
,
我用 9
的设备,试了下 同样 image list
没有找到 MapKit
,respondsToSelector
= 0
anos
(anos)
2017 年12 月 15 日 08:44
#15
好吧,水落石出,万分感谢,做梦都没有想到是在MapKit里啊,因为我是在逆向UIScrollView里的某一个方法看到这个方法的,image list 真是个好东西
刚才还发现我在老项目调用 id valuedoubleBounds = [self.view.layer performSelector:NSSelectorFromString(@“doubleBounds”)]; 还是有问题的,居然返回的是一个CALayer对象,这个还是不可靠,最后还是通过下面的代码得到真实的值:
SEL selector = NSSelectorFromString(@"doubleBounds");
IMP imp = [self.view.layer methodForSelector:selector];
CGRect (*func)(id, SEL) = (void*)imp;
CGRect doubleBounds = func(self.view.layer, selector);
NSLog(@"doubleBounds is %@", NSStringFromCGRect(doubleBounds));
搜了一下老项目的代码,果然是有一个地方写了 #import “MapKit/MapKit.h”,不过是在SDWebImage中,没见项目配置中添加有MapKit.framework,而新建的项目必须要添加这个framework才会不崩,猜测前者是某个第三方framework自行添加了MapKit.framework吧
anos
(anos)
2017 年12 月 15 日 08:47
#16
大神就是大神, 有关键字就好说了,新技能Get:
#import <objc/runtime.h>
#include <dlfcn.h>
#include <objc/objc.h>
Dl_info info;
if (dladdr(imp, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}
结果:
dli_fname: /System/Library/Frameworks/MapKit.framework/MapKit
dli_sname: <redacted>
dli_fbase: 0x194256000
dli_saddr: 0x1943c7c0c
原来不知道,现在好像知道了点,非常感谢。
用 _shortMethodDescription
找地址, 用 image lookup
去定位了
(lldb) image lookup -a 0x18bd06218
Address: MapKit[0x000000018b116218] (MapKit.__TEXT.__text + 1068056)
Summary: MapKit`-[CALayer(MKDoubleLayer) doubleBounds]
``
SDWebImage
上的 .podspec
文件,确实指明了依赖 MapKit
anos
(anos)
2017 年12 月 15 日 09:20
#19
但是我这里的老项目集成 SDWebImage 并不是通过pod集成的