快乐星球发车了——Hybrid 框架设计看一遍就会!

作者 | 李保君

嗨,我是ucself,一名大前端开发工程师。

项目使用技术发展历史

随着大前端技术的快速发展,项目历史包袱的遗留就会产生日益健全的 SDK 和项目框架。以文章的形式回忆和分享项目中使用技术发展要点,也算是工作,学习的产物。

以企鹅医生 App 为例,以下为 App 框架设计发展要点:

  • 原生 Native 技术开发

  • Native + Hybrid 技术开发

  • Native + Hybrid + React Native 技术开发

  • Native + Hybrid + React Native + flutter 技术开发

技术使用不是简单的把各种技术柔和在一个就行了,他们之间需要通信,规则,层次调用。今天先分享一下 Native + Hybrid 的框架设计。

什么是 Hybrid

Hybrid 从外观上来看是一个 Native UI,实则只有一个 WebView 里面访问的是一个使用 HTML5+CSS+JavaScript 做业务开发的 Web UI,即是 Native 的框架加上 Web 的内容开发方式。

Native,Hybrid 对比


HybridNative
开发成本
维护更新简单复杂
市场认可认可
体验
跨平台
平台特性
复杂动画

Hybrid 类型

1、Controller 主体型:整个页面是 Web View,穿插 Native 功能,主要以网页语言编写,这也是项目中绝大多数业务使用类型。

2、View 型:在同一个 View 内,Native View 和 Web View 为同时出现。比如:当 Native 未给 H5 提供复杂的导航栏渐变协议,而 H5 复杂的 UI 已经完成,这时候就需要使用 View 型 Native 来实现导航栏渐变,H5 实现业务。

Hybrid 架构设计

一、架构图

Hybrid 设计主要分为三个模块:H5 模块,Hybrid SDK 模块,Native 模块。如下架构图:

H5:H5 业务模块,主要让 SDK 注入方法/对象,方便 H5 业务调用(回调) SDK 响应的业务功能。

Hybrid SDK:SDK 模块,主要任务是注入 H5,注入 Native 需要调用和回调方法;实现基础服务的协议(如:header,forward,back,modal,dismiss,pageshow,pagehide)。

Native:Native 模块,主要响应 H5 调用 SDK 的时候,SDK 无法满足的协议进行扩展,此模块与 SDK 调用和回调。

二、时序图

时序图可以清楚的了解到业务调用流程关系。如下时序图:

根据时序图从以下几个关键技术点进行分享:

  • Native 回调事件注入

  • SDK 离线更新机制

  • SDK 与 H5 通讯机制

  • SDK 通讯流程

2.1 Native 回调事件注入

最开始在功能满足业务需求的时候,还未去实现 Native 回调事件注入。

随着业务的发展 H5 页面越来也多,需要 SDK 对 Native 做一些必要的响应,如:

  • 页面加载开始

  • 页面加载结束

  • 页面加载失败

根据业务增加,还可以继续增加回调事件注入

/// 命令扩展
public protocol HybridMethodProtocol {

    /// 页面加载失败所需操作
    ///
    /// - Parameter command: 命令对象
    func didFailLoad(viewController: HybridViewController)

    /// 加载等待开始  业务需要重写
    func startWait()

    /// 加载等待结束  业务需要重写
    func stopWait()
}
2.2 SDK 离线更新机制

在线访问 url 已经满足了业务功能需求,为了响应性能,提高体验 SDK 也做了离线更新机制。

A、获取资源文件压缩包

首先请求 H5 打包生成的 json 数据,并对 json 数据进行分析与本地 json 数据进行对比,如果版本改变则下载 json 数据中的压缩包,解压存储到本地。

{
  "name": "healthapp-1.0.2",
  "version": "1.0.2",
  "appName": "healthapp",
  "source": [
    {
      "id": "5b2a1ff5374a4600d476ec72",
      "key": "app-health-1.0.1",
      "name": "app/health",
      "version": "1.0.1",
      "bundle": "http://web-dev.doctorwork.com/ios/resources.zip"
    },
    {
      "id": "5b2a2103374a4600d476ec74",
      "key": "rapp-health-1.0.1",
      "name": "rapp/health",
      "version": "1.0.1",
      "bundle": "http://web-dev.doctorwork.com/ios/resources.zip"
    }
  ]
}

B、请求拦截加载本地资源

首先注册拦截协议,用于拦截 url 请求的回调


//设置拦截回调
if HybridConfiguration.default.isRegisterURLProtocol {
    URLProtocol.registerClass(HybridURLProtocol.self)
    URLProtocol.wk_registerScheme("http")
    URLProtocol.wk_registerScheme("https")
}

在拦截回调中进行离线逻辑拦截判断,匹配到本地存在改 url 请求的文件直接返回本地文件 response,如下时序图:

经过对 WKWebview 的测试,WKWebview 包含了内存缓存机制,如果是内存中存在缓存会直接返回内存中的资源。

SDK 与 H5 通讯机制

SDK 与 H5 通讯方式有很多种:

  • URL scheme

  • JavaScriptCore

  • ScriptMessageHandler

分享一下各个方式的机制

A、URL scheme

URL scheme 通讯方式是 Native 端拦截 url 请求通过获取 scheme 名称进行分析处理业务。

js 端发送命令:

loadURL(
  "hybridProtocol://shareClick?title=分享的标题&content=分享的内容&url=链接地址&imagePath=图片地址"
);

Native 端进行拦截并响应业务需求

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL * url = [request URL];
    if ([[url scheme] isEqualToString:@"firstclick"]) {
        NSString *host = url.host;
        NSArray *params =[url.query componentsSeparatedByString:@"&"];

        NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
        for (NSString *paramStr in params) {
            NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];
            if (dicArray.count > 1) {
                NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                [tempDic setObject:decodeValue forKey:dicArray[0]];
            }
        }
        NSLog(@"tempDic:%@",host);
        NSLog(@"tempDic:%@",tempDic);
        return NO;
    }
    return YES;
}

B、JavaScriptCore

JavaScriptCore 是 Native 系统提供的 API,向 H5 页面注入方法,H5 执行注入的方法做业务响应。

Native 端获取上下文会话并注入方法到 H5


- (void)addShareWithContext:(JSContext *)context
{
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"shareClick"] = ^() {
        NSArray *args = [JSContext currentArguments];

        if (args.count < 3) {
            return ;
        }

        NSString *title = [args[0] toString];
        NSString *content = [args[1] toString];
        NSString *url = [args[2] toString];
        // 在这里执行分享的操作

        // 将分享结果返回给js
        NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
        [[JSContext currentContext] evaluateScript:jsStr];
    };
}

H5 端执行注入的方法

shareClick("测试分享的标题", "测试分享的内容", "url=http://www.baidu.com");

C、ScriptMessageHandler

ScriptMessageHandler 也是 Native 系统提供的 API,向 H5 页面注入方法,H5 执行注入的方法做业务响应。经过测试使用区别在于 H5 开始加载的时候 ScriptMessageHandler 就注入了方法

Native 使用 ScriptMessageHandler 方法注入到 H5


[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"shareClick"];

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"body:%@",message.body);
    if ([message.name isEqualToString:@"ScanAction"]) {
        NSLog(@"分享业务");
    }
}

H5 端执行注入的方法

window.webkit.messageHandlers.Share.postMessage({
  title: "测试分享的标题",
  content: "测试分享的内容",
  url: "url=http://www.baidu.com",
});

综上,Native 与 H5 的通讯方式选择了 messageHandlers 注入方式。以上三种方式 Native 回调 H5 是 都是 webView 执行 js 方法进行回调或者协议中传入执行的回调 js 方法。

SDK 通讯流程

在业务通讯方面设计原则是:SDK 能完成的业务自行完成,不能完成的交给业务 Native 去完成。具体实现逻辑如下时序图:

SDK 业务为功能业务或者依赖 SDK 的业务,如:

  • Header

  • Forward

  • Back

  • Modal

  • Dismiss

  • Pageshow

  • Pagehide

Native 业务为项目中需要实现的需求业务,如:

  • Device

  • Location

  • Share

  • Camera

  • Clipboard

  • 等等

其他实现技术点

  • 文件操作增,删,压缩,解压。

  • NSURLProtocol

  • NavigationBarTransition

  • 动态执行方法

  • ScriptMessageHandler

  • NSLayoutConstraint

  • estimatedProgress

还有很多技术实现细节就不一一描述了。

总结

不同的 Native 需要针对不同的平台使用不同的开发语言(如使用 Objective-C、Swift 开发 iOS 应用,使用 Java 等开发 Android 应用),而 Hybrid 可开发能够在不同平台上部署的类原生应用。

由于 Hybrid App 结合了 Native App 良好用户交互体验和 Web App 跨平台开发的优势,非常有利于前端介入,非常适合业务快速迭代,Hybrid App 越来越多公司在使用。

全文完


以下文章您可能也会感兴趣:

我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值