最佳使用实践-离线包

离线包简介

通过 TMF 的离线包组件,可以将网页的静态资源(html、js、css、图片等)缓存在本地,当用户访问 H5 页面时,这些资源都不需要从服务器即时下载,离线包组件会拦截 WebView 的资源请求并直接读取本地的离线资源,达到“瞬间秒开”的效果。

TMF 控制台实现了离线包的自动打包、状态管理和发布功能,支持推拉结合的更新方式及增量更新机制,可按多种维度进行灰度下发,且能便捷地按 H5 的版本采集灰度数据,对不同版本的业务数据进行对比分析。对于重要业务(如一级页面),还可以直接将离线包预置在发布包中,首次进入页面无需下载即可使用,大幅提升 H5 业务的用户体验。当本地离线包没有准备好时,则直接访问在线资源,不影响正常使用。

离线包最佳实践

规划您的离线包

离线包分类

TMF离线包可以分为两种类型:

  • 主包:一个或一组业务对应的H5应用离线资源合集。
  • 公共包:多个主包的公共资源,可供多个主包共同使用。

主包与公共包使用规则:

  1. 主包之间不能相互依赖,主包资源为业务单独所有。
  2. 一个主包可以依赖多个公共包。

按照资源类型规划您的离线包

  1. 将多个H5应用的公共资源、基础库提取为公共包,供多个业务共同使用。
  2. 为了减少公共包更新频率,将公共资源进一步拆分为稳定公共资源与易变公共资源,根据变化频率拆分为不同的公共包。
  3. 根据H5应用业务划分,将不同应用或者不同业务拆分为独立的业务主包。
  4. 考虑到离线包更新下载效率问题,尽量控制离线包的大小,建议大小为2MB左右。

离线包打包

请参考打包离线包文档进行离线包打包操作。

预置离线包

请参考预置离线包文档完成离线包本地预置功能。

打开离线包

概念说明

  • BID: 离线包ID。
  • URL: 离线包业务入口URL,对应H5应用的主页面路径。

离线包URL规则

假设离线包对应的H5应用主页面路径为

http://pimweb.cs0309.3g.qq.com/testAk/index.html

离线包BID为weboffline_test_123。 使用离线包的接口检查更新、下载和加载时,URL分为两种情况:

  • 第一种
    url?_bid=xxx,表示访问这个 URL 时,它所需要的资源(例如图片、js 文件)会先从本地 bid 为xxx的离线包资源寻找,如果存在就加载本地资源,否则访问服务端资源。该方式URL如下:

    http://pimweb.cs0309.3g.qq.com/testAk/index.html?_bid=weboffline_test_123
    
  • 第二种,依赖公共包资源
    url?_bids=main+depends,main 表示主包,主包必须放在最前面(index.html 资源所在的包),depends 表示依赖包(公共资源所在的包)。

    访问这个 URL 时它所需要的资源(例如图片、js 文件)会先从本地 BID 为 main 主包中加载,然后再到依赖包 depends 中加载,如果本地没有则访问在线资源。假设离线包依赖的公共包BID时common,URL如下:

    http://pimweb.cs0309.3g.qq.com/testAk/index.html?_bids=weboffline_test_123+common
    

初始化

具体初始化流程请参考《离线包》接入手册。

加载离线包

Android
  1. 使用loadUrlAsync 方法将 URL_WITH_BID_PARAM 转换为离线包 URL,并使用 webview 加载转换后的 URL。其中URL_WITH_BID_PARAM获取方法请参考离线包URL规则

    loadUrlAsync默认会触发离线包检查更新,合理的检查更新时机及更新策略请参考检查离线包更新

    mOfflineManager.loadUrlAysn(URL_WITH_BID_PARAM, new SimpleCallback<String>() {
        @Override
        public void callback(String transedUrl) {
            webview.loadUrl(transedUrl);
        }
    });
    
  2. 创建 H5 容器,H5 容器的 WebView 需要重写 WebViewClient 的 shouldOverrideUrlLoading 方法,在该方法中需要使用 OfflineManager 类中的 shouldInterceptRequest 方法检查并使用本地离线包中的资源。

    OfflineManager 类中的 shouldInterceptRequest 方法使用如下:

    private class TestWebViewClient extends WebViewClient {
           @Override
         public WebResourceResponse shouldInterceptRequest(final WebView view, final String url) {
               TMFWebResourceResponse response = mOfflineManager.shouldInterceptRequest(url);
               if (response != null && response.getResourceResponse() != null) {
                     return response.getResourceResponse();
               }
             //注意这里必须返回父类的shouldInterceptRequest,不能直接返回null
              return super.shouldInterceptRequest(view, url);
        }
     }
    
iOS
  1. 创建包含WebView的ViewController,并遵守TMFWebOfflineWebViewControllerProtocol协议创建tmf_webOfflineHandler。同时实现WebView的代理。

  2. 使用determinedURLWithURL:方法对originURL进行处理,返回webview最终加载的URL。

    NSURL *determinedURL = [self.tmf_webOfflineHandler determinedURLWithURL:originURL];  
    // 由 WebOffline Handler 来决定最终要访问的 URL,例如开启 fallback 功能,此处会对 URL 进行转换
    NSURLRequest *request = [NSURLRequest requestWithURL:determinedURL];
    [self.webView loadRequest:request];
    
  3. 在webView的代理方法中,设置离线包拦截。

    - (void)webView:(WKWebView *)webView
        decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
                        decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        // Handle the WebOfflineHandler
        [self.tmf_webOfflineHandler handleRequest:navigationAction.request];
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    

使用公共包

如果多个离线包使用了相同的图片或css资源,可以将公共的资源放置在公共包中来降低离线包的整体大小。公共包打包及上传的步骤如下:

  1. 参考离线包打包步骤,离线包资源文件压做成离线包。
    undefined

  2. 修改离线包的加载URL,在bid信息中添加上公共包信息(本例中的common)。

    NSString *homeURLString = [NSString stringWithFormat:@"https://3gimg.qq.com/webapp_scan/TMF/TMF_intro/index.html?_bids=welcome+common&_t=%ld", (long)[[NSDate date] timeIntervalSince1970]];
    
  3. 在TMF控制台中的离线包模块新增业务。注意bid包类型选择公共包。
    undefined

  4. 在需要使用公共包资源的位置,添加所需资源的绝对路径(全路径)。
    undefined

  5. 升级本地离线包(本例中的welcome)后,可以观察到新离线包使用了公共包中的图片资源。
    undefined

离线包升级

灰度更新

离线包发布时,可以先进行灰度下发,测试无异常之后再进行正式下发。离线包灰度发布步骤如下:

  1. 在控制台中选择需要进行下发的离线包,然后进入创建推送任务阶段。
    undefined

  2. 在推送的推送对象栏目,选择用户账号,填入灰度测试用户账号。
    undefined

  3. 在用户未上报用户账号信息或者上报的用户账号信息与推送的用户账号信息不一致时,无法拉取到新版本离线包信息。
    undefined undefined

  4. 在用户上报与推送的用户账号一致的账号信息后,终端可以拉取到新版本的离线包信息。
    undefined undefined undefined

主包升级注意事项

  1. 主包升级如果依赖新版公共包,请同时更新公共包。
  2. 客户端已经检测到主包更新,但还未下载完成时会触发fallback地址流程,需遵守fallback规范,所有相对路径资源需完整打包进主包,否则使用 fallback_url时会找不到该资源。
  3. 主包使用公共包中的资源必须使用完整URL,不能是相对路径。

公共包升级注意事项

公共包是被多个离线包共同依赖的,因此公共包升级一定要考虑兼容所有离线包,包括旧版本离线包,原则上公共包中资源只增不减。

回滚离线包

在线上离线包出现异常时,可以通过回滚离线包功能。离线包回滚步骤如下:

  1. 当前最新版本离线包出现异常,需要进行回滚。
    undefined

  2. 在控制台中找到问题离线包的发布任务,点击右侧回滚按钮进行回滚。
    undefined

  3. 回滚任务会自动选择低版本离线包,您也可以手动选择其它版本进行回滚
    undefined

  4. 回滚任务的推送对象与被回滚任务的推送对象一致,无需进行推送对象设置。
    undefined

检查离线包更新

离线包检查更新支持如下几种方式:

  1. 打开离线包时自动触发检查。
  2. 通过推送下发触发检查。
  3. 在合适的时间手动触发,支持全部、批量、指定离线包检查更新。手动触发检查更新方式可参考《离线包接入手册》

所有检查更新动作默认都会受检查更新频率限制,您可以通过手动更新触发强制更新。手动触发强制检查更新方法:

  • Android
// 指定离线包检查更新
UpdateSetting setting = new UpdateSetting();
setting.ignoreFreqLimit = true;//绕过更新频率控制
mOfflineManager.checkLatestUpdate(bid, setting, new DefaultUpdateCallback());
  • iOS
// 指定离线包检查更新
TMFWebOfflineServiceOptions *options = [TMFWebOfflineServiceOptions options];
options.ignoresFrequency = YES;
[TMFWebOfflineService checkAndUpdateWithBID:@"bid" options:options completionHandler:^(BOOL isUpdated, NSError * _Nullable error) {
        // do something.
}];

检查更新时机建议:

  1. 打开离线包是触发检查更新,该机制默认是打开的。
  2. 离线包升级时默认下发推送,触发推送更新流程。
  3. 对于使用频率较高的离线包,推荐使用预检查机制,比如在程序启动时就触发首页离线包检查更新,但该方式需要谨慎使用,启动时触发过多离线包检查更新会占用网络与计算资源,影响用户体验。

下载离线包

仅Wi-Fi下载(仅Android)

Android离线包支持设置仅Wi-Fi下载,具体设置方法如下:

UpdateSetting setting = new UpdateSetting();
setting.downloadOnlyInWiFi = true;
mOfflineManager.checkLatestUpdate(bids, setting, new DefaultUpdateCallback());

离线包更新推送下载配置

离线包更新推送下载支持三种方式:

  • 忽略推送
  • 收到推送时立即下载离线包
  • 收到推送时仅Wi-Fi下载离线包

默认为收到推送时立即下载离线包,如您需调整策略,请参考如下设置方法:

  • Android
public class OfflineConfig {

    /**
     * 接收到离线包推送时忽略
     */
    public static final int DOWNLOAD_IGNORE_ON_PUSH = 1;
    /**
     * 接收到离线包推送时立刻下载离线包
     */
    public static final int DOWNLOAD_RIGHTNOW_ON_PUSH = 2;
    /**
     * 接收到离线包推送时Wi-Fi环境下才下载离线包
     */
    public static final int DOWNLOAD_ONLY_WIFI_ON_PUSH = 3;
}

OfflineManager.init(context, 
    OfflineConfig.builder(SharkService.getSharkWithInit())
                //其它设置
                .downloadModeOnPush(OfflineConfig.DOWNLOAD_ONLY_WIFI_ON_PUSH)
                .build());
  • iOS
typedef NS_ENUM(NSInteger, TMFWebOfflinePushHandlePolicy) {
    TMFWebOfflinePushHandlePolicyNone = 0,              ///< 收到推送后不更新,表示SDK不处理推送,同时将推送广播
    TMFWebOfflinePushHandlePolicyWiFiOnly = 1,          ///< 收到推送后仅在Wi-Fi下更新
    TMFWebOfflinePushHandlePolicyWiFiAndCellular = 2,   ///< 收到推送后任意网络下更新
};
// 离线包启动
TMFWebOfflineConfiguration *configuration = [TMFWebOfflineConfiguration configuration];
configuration.pushHandlePolicy = TMFWebOfflinePushHandlePolicyWiFiAndCellular;
[TMFWebOfflineService activateWithConfiguration:configuration];

设置离线包存储位置(仅安卓)

Android离线包支持外置和内置两种存储,默认是存储在内置存储中的,如果您想调整为外置存储,方法如下:

OfflineManager.init(context, 
    OfflineConfig.builder(SharkService.getSharkWithInit())
                //其它设置
                .storeInSDCard(true)
                .build());

注意注意:外部存储路径也是应用沙盒路径,没有读写权限问题,但可能因为外部存储被拔出导致离线包不生效,建议您使用内置存储。

移除离线包

为了减少应用存储占用,您可以将不再使用的离线包移除。具体移除方法请参考《离线包》接入手册。

离线包在线资源与fallback资源的关系

fallback地址组成

一个完整的fallback地址有两部分组成,Fallback Base URLOriginal Path。Fallback Base URL也是由CDN地址和离线包信息组成的。
undefined

使用fallback的离线包加载

离线包加载流程:

undefined

H5页面问题修复

iOS如何开启离线包调试日志

  1. 设置合适的离线包的logLevels

    离线包日志等级分为Debug、Info、Warn、Error。例如 TMFWebOfflineService.logLevels = TMFBaseCoreLogLevelDebug | TMFBaseCoreLogLevelInfo表示输出离线包的Debug和Info日志。如果想输出全部的日志,可以使用TMFBaseCoreLogLevelAll

  2. 合理地开启/关闭TMFBaseCore的日志筛选功能。

    TMFBaseCoreallowBaseCoreLogFilter可设置是否对离线包的日志进行筛选,且默认开启。它和TMFLogOptions共同控制是否对离线包的控制台日志进行筛选。

  3. XCode筛选离线包日志
    undefined

iOS JS报错导致白屏问题修复

  1. Safari的设置中开启开发选项。
    undefined

  2. 点击开发选项,选择需调试的页面。
    undefined

  3. 来源选项,还可以添加断点进行调试。
    undefined

离线包校验失败问题修复

iOS

TMFWebOfflineFileVerifierErrorDomain

错误信息 错误码 说明
TMFWebOfflineFileVerifierErrorPublicKeyInvalid -1 离线包公钥无效。可能是没有设置公钥或者公钥格式错误。
TMFWebOfflineFileVerifierErrorPackageJsonInvalid -2 找不到离线包文件的Hash记录文件,无法校验。
TMFWebOfflineFileVerifierErrorSignatureLoss -3 找不到离线包签名文件,无法校验。
TMFWebOfflineFileVerifierErrorSignatureInvalid -4 离线包校验失败,最常见的是公私钥不匹配。
TMFWebOfflineFileVerifierErrorFilesTampered -5 校验文件或目录出现问题,退出校验。

问题修复

  • TMFWebOfflineFileVerifierErrorPublicKeyInvalid
    1. 检查终端是否设置了公钥文件。
  • TMFWebOfflineFileVerifierErrorPackageJsonInvalid
    1. 检查离线包服务部署是否出现异常。
  • TMFWebOfflineFileVerifierErrorSignatureLoss
    1. 检查离线包服务部署是否出现异常。
  • TMFWebOfflineFileVerifierErrorSignatureInvalid
    1. 如果更换终端公钥文件,修改完毕后直接运行即可修复。
    2. 如果修改控制台私钥文件,则需要重新上传离线包并下发。

Android

校验错误码

错误信息 错误码 说明
DOWNLOAD_CODE_ERROR_S_FAIL 5 离线包签名校验失败
DOWNLOAD_CODE_ERROR_FULL_PACKAGE_CHECK_FAIL 6 离线包整包MD5校验失败

问题修复

  • DOWNLOAD_CODE_ERROR_S_FAIL 该错误在关闭快速校验时才可能出现,请检查离线包公钥是否配置正确。
  • DOWNLOAD_CODE_ERROR_FULL_PACKAGE_CHECK_FAIL 该错误在打开快速校验时才可能出现,可能是下载传输过程出错导致,请稍后重试。
快速校验设置

快速校验打开后,只校验离线包MD5,不会校验离线包签名信息,效率更高。Android默认实现是打开快速校验的,如果您想要更高的安全性,可以关闭快速校验。关闭方法如下:

OfflineManager.init(context, OfflineConfig.builder(SharkService.getSharkWithInit())
     //其它设置
     .quickVerify(false)
     .build());

iOS页面请求数据丢失

由于离线包的工作机制原因,H5页面的请求会被拦截,引起如post请求body丢失问题。解决此情况可采用下面两种方案:

  • 使用TMFWKWebView替换WKWebView

  • 在进入第三方页面是停止离线包拦截,离开第三方页面是继续拦截。

    • 停止拦截

      [TMFWebOfflineService pauseHandler];
      
    • 开启拦截

      [TMFWebOfflineService resumeHandler];
      
Copyright © 2013-2023 Tencent Cloud. all right reserved,powered by GitbookUpdate Time 2023-08-31 14:46:07

results matching ""

    No results matching ""