📄
Henry
  • Henry的神秘小屋
  • 其他
    • 字节码与机器码的区别?
  • ObjectiveC
    • NSInvocation
    • 检测OC项目中未使用的方法
    • Method Selector
    • 消息转发
  • Swift
    • 检测Swift项目中未使用的类 方法 属性
    • NSCoding
    • Mirror
    • JSONEncode JSONDecode
    • Any AnyObject AnyClass
    • is as? as! as
  • Cocoapods
    • 看懂Podfile.lock文件
    • 在编写的Pod中使用宏预编译
  • iOS
    • 苹果应用 保持画面流畅
    • 关于计算机展示图像的一些问题
    • @testable
    • iOS中URLRequest的缓存策略
    • CodePush接入流程
    • H5在WKWebView中读取沙盒文件
    • FDLog App客户端日志系统
    • 如何实现JSBridge基于WKWebView
    • 网络请求各个指标的度量
    • iOS13 UIModalPresentationStyle
    • 实现H5离线包机制
    • NSURLProtocol 拦截器
    • Framework
    • Lock
    • CFNetwork NSURLSession NSURLConnection
    • setNeedsLayout layoutIfNeeded layoutSubviews
    • StackView
    • Flutter Method Channel:从Dart到Native调用链
    • JSONSerialization.ReadingOptions
    • JSONSerialization.WritingOptions
    • RunLoop高级2
    • RunLoop高级1
    • RunLoop中级
    • RunLoop初级
    • LineBreak AutoShrink
    • 如何给H5出WebView调试包
    • TODO、FIXME、!!!、???、MARK
    • Operation的使用
    • UserDefault
    • 了解WKWebView
    • 输出日志信息到系统控制台
    • Float Double 失去精度问题
    • 使用xcodebuild命令打包导出
    • 在iOS项目中使用C++定义的模块
    • 证书问题
    • 创建常驻线程
  • 源码
    • 阅读PINCache源码
    • 解读AspectHook
    • HandyJSON是如何实现的?
  • 汇编
    • 看懂汇编
由 GitBook 提供支持
在本页
  • 前言
  • 流程:
  • 总结:

这有帮助吗?

  1. iOS

实现H5离线包机制

上一页iOS13 UIModalPresentationStyle下一页NSURLProtocol 拦截器

最后更新于5年前

这有帮助吗?

当前环境: Xcode10.0 Swift4.2 iOS SDK 12.1

H5 本地包下载:

前言

距离我做完离线包机制已经一周左右了,因为整个离线包含有 H5,App,后台一起协作完成,下面这里用到的技术的总结。

使用的技术点:

  1. 文件管理

  2. 文件下载

整体流程:

  1. H5 发布离线包

  2. App 下载离线包到本地

  3. 离线包平台[发版/回滚/禁用]

因为我们的 Job 是做 APP 的,所以我们会着重说 APP 相关的流程。

流程:

下面是我们的离线包,在 App 的生命周期内的运作。

对于 App 来说,总体来说可以分两步

第一步: 下载离线包到指定的本地位置,这里我用一张图片说明,我本地下载完的路径是什么样的。

我们去服务器上传的参数和返回的参数是什么呢? 下面的数据结构展示了 App 是如何与服务器端进行交互和逻辑处理的。

具体下载流程: 详细操作

  1. 首先 APP 启动的时候会开启常驻线程,每间隔一段时间会去服务器请求一次,来更新新包,下面就是 入参 和 出参,服务器可以下发不允许使用离线包来停用它。

  2. 当无本地包的时候,会启用在线包来进行容错,算是个兜底方案。

  3. App 上架的时候的 ipa 中是没有离线包的,都是通过网络下载的,因为防止下载包过大。

上传参数数据格式!

{
    "data":{
        "appCode":"SomeAppName", //APP标识 与服务器 商定
        "appVer":"1.2.0", //APP 版本 
        "platform":"ios", //手机平台
        "h5vers":[ //H5版本列表
            {
                "moduleId":"10010", // 业务编号
                "moduleVer":"1.0.4", // 版本
                "isActive": true // 是否启用离线
            },
            {
                "moduleId":"10020",
                "moduleVer":"1.0.2",
                "isActive":1
            },
            {
                "moduleId":"10030",
                "moduleVer":"1.0.8",
                "isActive":3
            }
        ]
    }
}

服务器返回数据格式!

{
    "resultData":[
        {
            "moduleId":"10010", // H5业务号
            "packageUrl":"https://jsoneditoronline.org/aa.zip", // 完整包地址
            "packageMD5":"adfadfadfadfadfadfadfadf", //完整包哈希值
            "patchUrl":"https://jsoneditoronline.org/aa.zip", // 补丁包地址
            "patchMD5":"adfadfadfadfadfadfadfadf", // 补丁包哈希值
            "mode":1, // 下载模式 是完整包 还是补丁
            "isActive":true // 是否启动 离线包
        },
        {
            "moduleId":"10020",
            "packageUrl":"https://jsoneditoronline.org/aa.zip",
            "packageMD5":"adfadfadfadfadfadfadfadf",
            "patchUrl":"https://jsoneditoronline.org/aa.zip",
            "patchMD5":"adfadfadfadfadfadfadfadf",
            "mode":2,
            "isActive":true
        },
        {
            "moduleId":"10030",
            "packageUrl":"https://jsoneditoronline.org/aa.zip",
            "packageMD5":"adfadfadfadfadfadfadfadf",
            "patchUrl":"https://jsoneditoronline.org/aa.zip",
            "patchMD5":"adfadfadfadfadfadfadfadf",
            "mode":1,
            "isActive":false
        }
    ]
}

对 下面图片 说明: 首先会去服务器查询可用的离线包,然后拿到下载链接,将离线 zip 包下载到 tmp 文件夹下的 FD+UUID 的文件夹下,下面的目录用业务 Key 创建文件名字,里面装着离线 H5 Zip 包。 只不过图中的 已经被移动到 Document 文件目录下里了。

第二步: 加载 WebView 的时候插入离线包机制

具体来说就是我们加载 WebView 的时候判断一下再选择加载,这里我截取一下代码。

- (void)loadUrl: (NSString *)urlString
{
    NSURL *url = [NSURL URLWithString:urlString];

    FDH5OfflineEngine *share = FDH5OfflineEngine.share;
    BOOL isCan = [share isCanAccessOfflineH5WithUrl:url];
    // 是否能加载离线包
    if (isCan) {
        // 将在线的URL转换成离线的URL,这里我其实返回的是一个对象,对象里面包含离线路径和离线路径的根路径
        FDH5OfflineURL *sets = [share onlineUrlConvertToLocalUrlWithUrl:url];
        [self loadFileURL:[sets fileURL] allowingReadAccessToURL:[sets allowingReadAccessToURL]];
    }
    else {
        // 加载在线
        NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15];
        [self loadRequest:request];
    }
}

它在 App 中的整体流程我总结成了一张图如下:

说明: 当一个业务模块的其中一个方法触发的 scheme 跳转(路由实现),这个 scheme 是跳转到 WebViewController 的,会在加载WebView loadURL 的时候做上面的判断再去加载。

总结:

我相信这个方案肯定有些许问题,但是毕竟是我和小伙伴一起想出来并且实现的,并且也成功上线,后续迭代一点点迭代。 这里的 iOS 技术点,后面会分专门的文章逐一 Demo 总结。

常驻线程
多线程(Operation)
JSBridge
压缩解压缩
https://github.com/zColdWater/OfflinePack