最直接的解决办法
webview加载会先去查看该方法是否实现
NSObject添加一个扩展去实现webView:didCreateJavaScriptContext:forFrame:方法
- 问题
该方法属于苹果的私有方法,直接实现,有很大概率被苹果据掉
对上面的解决方法优化思路
该方案来源于对听云sdk的反编译代码分析
方案一
- 听云的sdk启动位置为main函数,
- 根据app的启动原理分析,mach-o加载结束加载sdk,runtime给NSObject添加webView:didCreateJavaScriptContext:forFrame:方法实现,此时注入js
- 如果需要上架,必须将 webView:didCreateJavaScriptContext:forFrame: 加密之后,反解密放入,直接显示该方法被拒可能性很大
- 这里只是表达主要思路和解决方案
#import "JSInjection.h"
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
@implementation JSInjection
+ (void)start {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//JSContext
Method imageNamedMethod = class_getClassMethod([NSObject class], @selector(webView:didCreateJavaScriptContext:forFrame:));
if (imageNamedMethod == nil) {
class_addMethod([NSObject class], @selector(webView:didCreateJavaScriptContext:forFrame:), class_getMethodImplementation([self class], @selector(test_webView:didCreateJavaScriptContext:forFrame:)),method_getTypeEncoding(imageNamedMethod));
}
});
}
- (void)test_webView:(id)unuse didCreateJavaScriptContext:(JSContext *)ctx forFrame:(id)frame
{
NSLog(@"js注入位置");
}
@end
调用位置
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "JSInjection.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
[JSInjection start];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
方案二
- 本方案基于上面的解决思路,如果不想写代码在main函数中,可以选择nsobject的分类+load方法中,和上面的代码基本类似
- 问题:听云没有采用这种方式的原因应该是sdk无法对该方法完全控制,如果直接在项目中使用,不需要sdk可以采用这种方式
网友评论