背景
上次对BeeHive的一些基本原理进行了一定的分析,BeeHive提供的不仅仅是一个第三方库,其主张的模块化编程思想对解决日益庞大的代码有着借鉴意义。
BeeHive提供了对AppDelegate的封装,开发者如果需要在AppDelegate回调中调用方法,则需要实现相应的Module,Module声明了特定的接口,从代码规范方面来看,这是一种非常好的设计方式。开发者不需要在Appdelgate堆积大量代码,AppDelegate当中会依次调用相应的Module,Module之间做到了相互隔离。在开发应用框架时,这种设计非常有借鉴意义。例如设计某个流程逻辑,框架需要保证流程按顺序执行,其顺序是规定好的,开发人员不能随意改变。但开发人员可以在某些节点上嵌入特定的代码,根据中间结果执行相应的操作。比如像很多情况下,需要自定义WebViewController。WebViewController的正常逻辑是加载网页页面,但现在需要增加很多额外的功能,例如:网址白名单、Js bridge等。之前在实现时,将白名单跟Js bridge都写在一块,Js Bridge的功能非常多,每次增加新功能时,都需要在WebViewController文件增加新的功能代码。给到其它项目组用的时候,更新的时候非常麻烦。不能真正做到webview的插件化。看到BeeHive后,想尝试一下使用模块化的思想对webView进行一次封装。
设计
首先需要定义一个ModuleProtocol,这里只实现6个接口
@protocol BHWebViewModuleProtocol <NSObject>
@optional
- (void)viewDidLoad:(BHWebViewContext *)context;
- (BOOL)shouldStartLoadWithRequest:(BHWebViewContext *)context;
- (void)webViewDidStartLoad:(BHWebViewContext *)context;
- (void)webViewDidFinishLoad:(BHWebViewContext *)context;
- (void)didFailLoadWithError:(BHWebViewContext *)context;
+ (NSInteger)moduleLevel;
@end
定义了一个BHWebViewManager用于管理Manager,其中定义了注册Module方法
@interface BHWebViewManager : NSObject
+ (instancetype)sharedManager;
// 给BHWebViewController 注册Module
- (void)registerDynamicModule:(Class)moduleClass;
- (void)registedAnnotationModules;
- (id )tiggerEvent:(BHWebViewModuleEventType)eventType withContext:(BHWebViewContext *)context;
@end
自定义webViewController,BHWebViewContext用于传递运行参数
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self loadRequest:_request];
BHWebViewContext *context = [[BHWebViewContext alloc] init];
context.webViewController = self;
[[BHWebViewManager sharedManager] tiggerEvent:BHviewDidLoad withContext:context];
// Do any additional setup after loading the view.
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
BHWebViewContext *context = [[BHWebViewContext alloc] init];
context.webViewController = self;
context.webView = webView;
context.request = request;
context.navigationType = navigationType;
id result = [[BHWebViewManager sharedManager] tiggerEvent:BHshouldStartLoadWithRequest withContext:context];
return [result boolValue];
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
BHWebViewContext *context = [[BHWebViewContext alloc] init];
context.webViewController = self;
context.webView = webView;
[[BHWebViewManager sharedManager] tiggerEvent:BHwebViewDidStartLoad withContext:context];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
BHWebViewContext *context = [[BHWebViewContext alloc] init];
context.webViewController = self;
context.webView = webView;
[[BHWebViewManager sharedManager] tiggerEvent:BHwebViewDidFinishLoad withContext:context];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
BHWebViewContext *context = [[BHWebViewContext alloc] init];
context.webViewController = self;
context.webView = webView;
[[BHWebViewManager sharedManager] tiggerEvent:BHdidFailLoadWithError withContext:context];
}
使用宏来注册Module,参数BHAnnotation来实现。
#import <Foundation/Foundation.h>
#ifndef BeehiveWebViewModSectName
#define BeehiveWebViewModSectName "BHWebViewMods"
#endif
#define BeeHiveWebViewDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
#define BeeHiveWebViewMod(name) \
char * k##name##_mod BeeHiveWebViewDATA(BHWebViewMods) = ""#name"";
@interface BHWebViewAnnotation : NSObject
+ (NSArray<NSString *> *)AnnotationModules;
@end
自定义插件
白名单功能
BeeHiveWebViewMod(BHWebViewWhiteListModule)
@implementation BHWebViewWhiteListModule
- (BOOL)shouldStartLoadWithRequest:(BHWebViewContext *)context
{
NSURLRequest *request = context.request;
NSString *scheme = [[request URL] scheme];
NSString *host = [[request URL] host];
if ([scheme isEqualToString:@"https"] )
{
if([host isEqualToString:@"www.baidu.com"])
{
return YES;
}
else
{
return NO;
}
}
return NO;
}
@end
js Bridge
BeeHiveWebViewMod(BHWebViewJsBridgeModule)
@implementation BHWebViewJsBridgeModule
- (BOOL)shouldStartLoadWithRequest:(BHWebViewContext *)context
{
NSURLRequest *request = context.request;
NSString *scheme = [[request URL] scheme];
NSString *host = [[request URL] host];
if ([scheme isEqualToString:@"exeJs"] )
{
if([host isEqualToString:@"showAlertView"])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"提示"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles: nil];
[alertView show];
}
}
return YES;
}
@end
通过借鉴BeeHive的设计,可以将webViewController实现Module化,白名单跟js Bridge可以实现插件化,通过宏来注册Module,在使用时,只需要将module代码添加到工程即可。