iOS 从WebView来看插件化设计思路

前言

在iOS开发过程当中,随着项目的愈来愈庞大,一些基础组件须要单独剥离出来。单独剥离出来的基础组件也会由于业务需求的不断变化而愈来愈臃肿难以维护。如何去解决这个问题,插件化的设计能够为你们提供一些思路。接下来我将以webView的插件设计为例。web

在成熟的项目中每每会采用封装好一个webView,复用于各个须要的地方。好处天然不言而喻,减小了冗余代码,统一规范,易于维护等。app

同时,webView每每须要和H5页面进行交互,交互的实现方式多种多样,在此不表。随着项目规模愈来愈大,针对不一样的业务需求,每每须要在webView中添加各类各样的交互逻辑,最后就致使webView愈来愈臃肿愈来愈难以维护。ui

为此,设计一套插件化的实现,来解决这个问题。 经过插件来赋予webView各类各样的能力,同时插件与webView解耦,结构上更易于维护和易懂。spa

思路

这里以webView和H5的交互为例。创造出来的每一个插件都对应一个Action。在H5将事件抛给webView的时候,webView将事件交给对应的插件去完成。插件

在此流程上,有两个须要关注的点。设计

  • webView如何将Action传递给对应实现的Plugin。
  • 对应的Plugin应该怎么实现。

插件的设计

到此,咱们须要分析插件的设计要求。code

  1. 插件须要有执行Action的能力。
  2. 插件要可以快速被找到。
  3. 插件生命周期要科学。减小资源的消耗。
  4. 插件的实现尽可能简单简洁,方便推广使用。

对此,咱们能够准备一个插件基类:webViewPlugincdn

/* 插件查询表 */
static NSMutableDictionary<NSString *, NSString *> *pluginsMapping;
+ (NSString *)actionName {
    return @"";
}
+ (void)registerPlugin {
    
    if (pluginsMapping == nil) {
        pluginsMapping = [NSMutableDictionary<NSString *, NSString *> dictionary];
    }
    [pluginsMapping setObject:NSStringFromClass(self) forKey:[self actionName]];
}
- (nullable __kindof instancetype)initWithHandlerName:(NSString *)handlerName
                                           parameters:(NSDictionary<NSString *, id> *)parameters
                                           forWebView:(webView *)webView {
    
    NSString *className = [pluginsMapping objectForKey:handlerName];
    Class clazz = NSClassFromString(className);
    if (clazz == nil || ![clazz isSubclassOfClass:WebViewPlugin.class]) {
        return nil;
    }
    
    WebViewPlugin *plugin = [[clazz alloc] init];
    plugin.handlerName = handlerName;
    plugin.parameters = parameters;
    plugin.webView = webView;
    return plugin;
}
- (void)startAction {
}

复制代码

基类中准备了4个方法:blog

一个是对应的Action的名称,其实也能够理解为每一个Plugin对应的key,在webView接收到事件之后,咱们须要经过这个Key来查找对应的Plugin。继承

第二个是注册方法,在这里能够看到我准备了一个静态的Dictionary,使用静态的Dictionary是由于这个字典能够单独存储在静态区,方便随取随用。

第三个就是对应的初始化方法。初始化方法中主要作的事情就是从存储好的注册表里根据外部传进来的key将对应的plugin初始化。

第四个就是plugin须要实现的Action。

到此Plugin的基类就完成了。经过继承并实现对应的方法来添加Plugin。

WebViewPluginClose,那它的实现就是:

+ (void)load {
    [self registerPlugin];
}

+ (NSString *)actionName {
    return @"close_webview";
}

- (void)startAction {
    [self.webView removeFromSuperview];
    
}

复制代码

在子类的实现中,我将插件的注册方法写在了load方法中。 load方法是项目代码加载之后每一个类都会调用的方法,而且父类先于子类。 因此在此添加注册方法免去了上层业务手动注册管理等操做。 同时实现了actionName也就是定义了对应的key,最后将操做放在了startAction中。

webView事件的分发

在webView接收到事件后,根据对应的Key去分发给相应的插件:

WebViewPlugin *plugin = [[WebViewPlugin alloc] initWithHandlerName:name parameters:params forWebView:self];

[plugin startAction];
复制代码

扩展总结

在此例子的基础上还能够根据业务的需求完善更多的设计。好比将消息数据统一分发给一个PluginManager,在PluginManager中又能够作消息转发数据预处理等等知足更复杂的场景需求。每一个插件也能够根据须要赋予不一样的能力,甚至规划更多类型的插件。

在此笔者借助webView的例子想向和你们分享的是插件化的这一设计思路。这样的设计思路不单单适用于webView等,一样也能够给UIView的组件或某个Controller等使用。在实现业务解藕的同时也让代码更加易于维护。

相关文章
相关标签/搜索