显著提高iOS应用中Web页面的加载速度 - 提前下载页面的关键资源(如JavaScript、CSS和图像)

news2024/11/22 22:07:50

在这里插入图片描述

手动下载并缓存资源是一种有效的方式,可以确保在需要时资源已经在本地存储,这样可以显著提高加载速度。

缓存整个 web 页面的所有资源文件

具体实现步骤

  1. 下载和缓存资源:包括 HTML 文件、CSS、JavaScript 和图像。
  2. 在应用启动时预加载资源
  3. 构建包含所有预加载资源的 HTML 字符串
  4. 加载构建的 HTML 字符串到 WKWebView

资源下载和缓存管理类

import Foundation

class ResourceDownloader {
    static let shared = ResourceDownloader()
    private init() {}
    
    func downloadResources() {
        let resources = [
            URL(string: "https://www.example.com/styles.css")!,
            URL(string: "https://www.example.com/script.js")!,
            URL(string: "https://www.example.com/image.png")!,
            URL(string: "https://www.example.com/index.html")!
        ]
        
        for resource in resources {
            downloadResource(from: resource)
        }
    }
    
    private func downloadResource(from url: URL) {
        let task = URLSession.shared.downloadTask(with: url) { localURL, response, error in
            guard let localURL = localURL else { return }
            
            do {
                let data = try Data(contentsOf: localURL)
                self.cacheResource(data: data, url: url)
            } catch {
                print("Failed to load resource: \(error)")
            }
        }
        task.resume()
    }
    
    private func cacheResource(data: Data, url: URL) {
        let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let fileURL = cacheDirectory.appendingPathComponent(url.lastPathComponent)
        
        do {
            try data.write(to: fileURL)
            print("Resource cached: \(fileURL)")
        } catch {
            print("Failed to cache resource: \(error)")
        }
    }
    
    func getCachedResource(for url: URL) -> Data? {
        let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let fileURL = cacheDirectory.appendingPathComponent(url.lastPathComponent)
        
        return try? Data(contentsOf: fileURL)
    }
}

在应用启动时预加载资源

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 预加载资源
        ResourceDownloader.shared.downloadResources()
        return true
    }
}

使用缓存的资源加载完整页面

import UIKit
import WebKit

class ViewController: UIViewController {
    
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        webView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(webView)
        
        // 构建完整的HTML内容
        if let htmlURL = URL(string: "https://www.example.com/index.html"),
           let cachedHTML = ResourceDownloader.shared.getCachedResource(for: htmlURL),
           let htmlString = String(data: cachedHTML, encoding: .utf8) {
            
            let completeHTMLString = embedCachedResources(in: htmlString)
            
            // 加载HTML内容到webView
            webView.loadHTMLString(completeHTMLString, baseURL: nil)
        } else {
            // 如果没有缓存,则加载远程 URL
            let request = URLRequest(url: URL(string: "https://www.example.com")!)
            webView.load(request)
        }
    }
    
    private func embedCachedResources(in htmlString: String) -> String {
        var modifiedHTMLString = htmlString
        
        // 嵌入预加载的CSS
        if let cssURL = URL(string: "https://www.example.com/styles.css"),
           let cachedCSS = ResourceDownloader.shared.getCachedResource(for: cssURL),
           let cssString = String(data: cachedCSS, encoding: .utf8) {
            let cssTag = "<style>\(cssString)</style>"
            modifiedHTMLString = modifiedHTMLString.replacingOccurrences(of: "<link rel=\"stylesheet\" href=\"styles.css\">", with: cssTag)
        }
        
        // 嵌入预加载的JavaScript
        if let jsURL = URL(string: "https://www.example.com/script.js"),
           let cachedJS = ResourceDownloader.shared.getCachedResource(for: jsURL),
           let jsString = String(data: cachedJS, encoding: .utf8) {
            let jsTag = "<script>\(jsString)</script>"
            modifiedHTMLString = modifiedHTMLString.replacingOccurrences(of: "<script src=\"script.js\" defer></script>", with: jsTag)
        }
        
        // 嵌入预加载的图像
        if let imageURL = URL(string: "https://www.example.com/image.png"),
           let cachedImage = ResourceDownloader.shared.getCachedResource(for: imageURL) {
            let base64Image = cachedImage.base64EncodedString()
            let imgTag = "<img src='data:image/png;base64,\(base64Image)' alt='Preloaded Image'>"
            modifiedHTMLString = modifiedHTMLString.replacingOccurrences(of: "<img src=\"image.png\" alt=\"Preloaded Image\">", with: imgTag)
        }
        
        return modifiedHTMLString
    }
}

详细说明

  1. 资源下载和缓存

    • 使用 URLSession 下载资源(包括HTML文件、CSS、JavaScript和图像),并将其缓存到本地存储。
    • 下载完成后,资源数据被写入本地存储,以便后续使用。
  2. 预加载资源

    • 在应用启动时调用 downloadResources() 方法,预先下载和缓存所需的资源。
  3. 使用缓存的资源加载完整页面

    • viewDidLoad() 方法中,通过 getCachedResource(for:) 获取缓存的HTML内容。
    • 使用 embedCachedResources(in:) 方法,将预加载的 CSS、JavaScript 和图像嵌入到 HTML 内容中。
    • 使用 webView.loadHTMLString(completeHTMLString, baseURL: nil) 加载修改后的 HTML 内容。

通过这种方式,可以确保在加载页面时直接使用本地缓存的资源,从而显著提高页面加载速度,提供更好的用户体验。


只缓存 CSS、JavaScript 和图像

只有 CSS、JavaScript 和图像是预加载的,而 HTML 文件是在打开 WKWebView 时才开始下载的。这种策略在某些情况下可能更加高效,尤其是当 HTML 文件需要动态生成或者频繁更新时。

为什么预加载 CSS、JavaScript 和图像?

预加载 CSS、JavaScript 和图像有几个优点:

  • 减少首次渲染时间:通过提前加载关键资源,可以显著减少页面首次渲染的时间,提高用户体验。
  • 减轻服务器压力:本地缓存的资源可以减少重复请求,减轻服务器的负载。
  • 提高离线体验:在某些情况下,即使没有网络连接,用户也能看到页面的一部分内容。

什么时候 HTML 文件在打开 WKWebView 时下载?

  • 动态内容:如果 HTML 文件内容是动态生成的(例如,包含个性化数据或实时更新的数据),那么在每次加载页面时请求最新的 HTML 文件是必要的。
  • 频繁更新:如果 HTML 文件内容频繁更新,预加载 HTML 文件可能会导致内容不一致。
  • 用户特定数据:某些应用需要根据用户的身份或状态生成不同的 HTML 内容。

完整的 Swift 代码实现

展示如何预加载 CSS、JavaScript 和图像,并在打开 WKWebView 时下载 HTML 文件。

import UIKit
import WebKit

class ViewController: UIViewController {
    
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 创建并配置 WKWebView
        let configuration = WKWebViewConfiguration()
        let urlSchemeHandler = LocalResourceHandler()
        configuration.setURLSchemeHandler(urlSchemeHandler, forURLScheme: "local")
        
        webView = WKWebView(frame: self.view.bounds, configuration: configuration)
        self.view.addSubview(webView)
        
        // 加载远程 HTML 文件
        if let htmlURL = URL(string: "https://www.example.com/index.html") {
            let request = URLRequest(url: htmlURL)
            webView.load(request)
        }
    }
}

class LocalResourceHandler: NSObject, WKURLSchemeHandler {
    
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        guard let url = urlSchemeTask.request.url else {
            return
        }
        
        // 仅处理特定的 URL 方案,例如 "local"
        guard url.scheme == "local" else {
            // 对于非 "local" 方案的请求,不处理
            return
        }
        
        if let data = ResourceDownloader.shared.getCachedResource(for: url) {
            let mimeType = determineMimeType(for: url)
            let response = URLResponse(url: url, mimeType: mimeType, expectedContentLength: data.count, textEncodingName: nil)
            urlSchemeTask.didReceive(response)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        } else {
            // 缓存资源不可用,发起网络请求
            downloadResource(from: url, urlSchemeTask: urlSchemeTask)
        }
    }
    
    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {}
    
    private func determineMimeType(for url: URL) -> String {
        switch url.pathExtension {
        case "css":
            return "text/css"
        case "js":
            return "application/javascript"
        case "png":
            return "image/png"
        default:
            return "text/plain"
        }
    }
    
    private func downloadResource(from url: URL, urlSchemeTask: WKURLSchemeTask) {
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                urlSchemeTask.didFailWithError(error)
                return
            }
            
            guard let data = data, let response = response else {
                urlSchemeTask.didFailWithError(NSError(domain: "LocalResourceHandler", code: 404, userInfo: nil))
                return
            }
            
            // 缓存资源
            ResourceDownloader.shared.cacheResource(data: data, url: url)
            
            // 返回资源
            urlSchemeTask.didReceive(response)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        }
        task.resume()
    }
}

class ResourceDownloader {
    static let shared = ResourceDownloader()
    private init() {}
    
    func downloadResources() {
        let resources = [
            URL(string: "https://www.example.com/styles.css")!,
            URL(string: "https://www.example.com/script.js")!,
            URL(string: "https://www.example.com/image.png")!
        ]
        
        for resource in resources {
            downloadResource(from: resource)
        }
    }
    
    private func downloadResource(from url: URL) {
        let task = URLSession.shared.downloadTask(with: url) { localURL, response, error in
            guard let localURL = localURL else { return }
            
            do {
                let data = try Data(contentsOf: localURL)
                self.cacheResource(data: data, url: url)
            } catch {
                print("Failed to load resource: \(error)")
            }
        }
        task.resume()
    }
    
    func cacheResource(data: Data, url: URL) {
        let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let fileURL = cacheDirectory.appendingPathComponent(url.lastPathComponent)
        
        do {
            try data.write(to: fileURL)
            print("Resource cached: \(fileURL)")
        } catch {
            print("Failed to cache resource: \(error)")
        }
    }
    
    func getCachedResource(for url: URL) -> Data? {
        let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let fileURL = cacheDirectory.appendingPathComponent(url.lastPathComponent)
        
        return try? Data(contentsOf: fileURL)
    }
}
在应用启动时预加载资源
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 预加载资源
        ResourceDownloader.shared.downloadResources()
        return true
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1827263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS从入门到精通——动画:CSS3动画执行次数和逆向播放

目录 任务描述 相关知识 动画执行次数 动画反向播放 编程要求 任务描述 本关任务&#xff1a;用 CSS3 实现loading效果。效果图如下&#xff1a; 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.动画执行次数&#xff0c;2.动画反向播放。 需要实现的效…

CSS从入门到精通——动画:CSS3动画延迟和完成后状态的保持

目录 任务描述 相关知识 动画状态 动画完成时的状态 动画延迟 编程要求 任务描述 本关任务&#xff1a;用 CSS3 实现小车等待红绿灯的效果。效果图如下&#xff1a; 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.动画状态&#xff0c;2.动画完成时的状…

mac下Xcode在iphone真机上测试运行iOS软件

最近一个需求需要在iPhone真机上测试一个视频直播的项目。 需要解决如何将项目 app 安装到真机上 在进行真机调试。 安装Xcode 直接在App Store上搜索Xcode安装即可。 关键是要安装Simulator。项目需要安装iOS17.5但是由于安装包太大&#xff0c;并且网络不稳定的原因。在Xco…

关于yolov5训练的那些事儿

1.YOLOv5 的模型系列包括从最小到最大的多种模型&#xff1a;YOLOv5n&#xff08;Nano&#xff09;&#xff0c;YOLOv5s&#xff08;Small&#xff09;&#xff0c;YOLOv5m&#xff08;Medium&#xff09;&#xff0c;YOLOv5l&#xff08;Large&#xff09;&#xff0c;以及 YO…

【Linux硬盘读取】Windows下读取Linux系统的文件解决方案:Linux Reader4.5 By DiskInternals

前言 相信做机器视觉相关的很多人都会安装 Windows 和 Linux 双系统。在 Linux 下&#xff0c;我们可以很方便的访问Windows的磁盘&#xff0c;反过来却不行。但是这又是必须的。通过亲身体验&#xff0c;向大家推荐这么一个工具&#xff0c;可以让 Windows 方便的访问 Ext 2/3…

Linux 文件的权限信息解读 chmod修改权限 数字序号表示权限

ls -l #列出当前文件 显示详细信息 drwxr-xr-x. 2 dpc test 6 Jun 15 07:45 test.txt共分为三部分 drwxr-xr-x.&#xff1a;表示文件和文件夹的权限信息dpc &#xff1a;文件&#xff0c;文件夹所属的用户test &#xff1a; 文件和文件夹所属的用户组 drwxr-xr-x 解读 d表示为…

实用软件下载:BetterZip 5最新安装包及详细安装教程

BetterZip是一款功能强大的Mac解/压缩软件&#xff0c;可以满足用户对文件压缩、解压、加密和保护等方面的需求。以下是关于BetterZip软件的主要功能、特点和使用方法的详细介绍&#xff0c;以及对其用户友好度、稳定性和安全性的评价。 安 装 包 获 取 地 址: BetterZip 5-安…

【尚庭公寓SpringBoot + Vue 项目实战】公寓管理(十一)

【尚庭公寓SpringBoot Vue 项目实战】公寓管理&#xff08;十一&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】公寓管理&#xff08;十一&#xff09;1、业务介绍2、逻辑模型介绍3、接口开发3.1、保存或更新公寓信息3.2、根据条件分页查询详细信息3.3、根据ID获…

深度学习(七)——神经网络的卷积操作

卷积操作 一、torch.nn中Convolution Layers函数的介绍 1. 参数介绍 nn.Conv1d: Conv取自Convolution的前四个字母&#xff0c;1d代表的是一个一维操作。 nn.Conv2d: 2d表示是一个二维的操作&#xff0c;比如图像就是一个二维的。 其余参数不常用&#xff0c;见官网文档&am…

分布式事务AP控制方案(下)

分布式事务控制方案 本篇文章给出一种要求高可用性&#xff08;AP思想&#xff09;的分布式事务控制方案 上篇回顾&#xff1a;点我查看 分布式事务控制方案1、前景回顾2、数据库和缓存的操作3、分布式文件系统1&#xff09;页面静态化2&#xff09;远程调用3&#xff09;调用…

adb卸载系统应用

1.进入shell adb shell2.查看所有包 pm list packages3.查找包 如查找vivo相关的包 pm list packages | grep vivo发现包太多了,根本不知道哪个是我们想卸载的应用 于是可以打开某应用,再查看当前运行应用的包名 如下: 4.查找当前前台运行的包名 打开某应用,在亮屏状态输入 …

卫星通讯助力船舶可视化监控:EasyCVR视频汇聚系统新应用

一、背景 随着科技的不断进步和社会治安的日益严峻&#xff0c;视频监控系统已经成为维护公共安全和提升管理效率的重要工具。传统的视频监控主要依赖于有线传输&#xff0c;但受到地域限制、布线成本高等因素的影响&#xff0c;其应用范围和效果受到一定限制。而卫星通讯传输…

学会python——显示进度条(python实例五)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、进度条显示 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、总结 1、认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读…

ComfyUI中使用 SD3 模型(附模型下载详细说明)

文章目录 背景安装方式一方式二 测试 背景 StabilityAI近日开源了Stable Diffusion 3 Medium&#xff0c;简称 SD3&#xff0c;该模型拥有着20亿参数。其特点如下&#xff1a; 提升了整体图片的质量、真实感提供了三种文本编码器可组合使用&#xff0c;有助于在性能和效率之间…

《大道平渊》· 拾肆 —— 不要为不属于你负责的事情负责

《平渊》 拾肆 "客观世界如是观照&#xff0c;控制自己&#xff0c;不要介入因果。" 美国开国总统华盛顿说过, 不要干涉欧洲事务。 可是他的后任都不听, 于是纷纷卷入了无穷的麻烦之中。 不要为不属于你负责的事情负责。 别人的行为和你有什么关系&#xff1f; 就…

Stable-Diffusion-WebUI 常用提示词插件

SixGod提示词插件 SixGod提示词插件可以帮助用户快速生成逼真、有创意的图像。其中包含&#xff0c;清空正向提示词”和“清空负向提示词、提示词起手式包含人物、服饰、人物发型等各个维度的提示词、一键清除正面提示词与负面提示词、随机灵感关键词、提示词分类组合随机、动…

<Rust><iced>基于rust使用iced库构建GUI实例:图片的格式转换程序

前言 本专栏是Rust实例应用。 环境配置 平台&#xff1a;windows 软件&#xff1a;vscode 语言&#xff1a;rust 库&#xff1a;iced、iced_aw 概述 本文是专栏第二篇实例&#xff0c;是一个图像格式转换程序&#xff0c;基于rust图像处理库image以及文件处理库rfd。 UI演示&…

Python读取wps中的DISPIMG图片格式

需求&#xff1a; 读出excel的图片内容&#xff0c;这放在微软三件套是很容易的&#xff0c;但是由于wps的固有格式&#xff0c;会出现奇怪的问题&#xff0c;只能读出&#xff1a;类似于 DISPIMG(“ID_2B83F9717AE1XXXX920xxxx644C80DB1”,1) 【该DISPIMG函数只有wps才拥有】 …

阿里新发布的UniAnimate现高效人像动画生成;在ComfyUI中使用Stable 3模型;音频版的gpt2o;将 PDF 文档转换为音频播客

✨ 1: UniAnimate 阿里新发布的UniAnimate通过统一的视频扩散模型&#xff0c;实现高效人像动画生成&#xff0c;支持长视频生成 UniAnimate 是一种专注于一致性人像动画生成的统一视频扩散模型。该模型通过映射参考图像、姿势指导和噪声视频到一个共同特征空间&#xff0c;实…

docker安装nginx并且加上映射

随机启动nginx&#xff0c;方便复制配置文件 docker run -p 80:80 --name nginx -d nginx:1.10将容器内的配置文件拷贝到当前目录 docker container cp nginx:/etc/nginx .别忘了后面的点 修改文件名称&#xff1a; mv nginx conf 把这个 conf 移动到/mydata/nginx 下 终止原…