File Downloads
This implementation allows users to download .ics
files (calendar events) from the LiSA Player running in a WebView, and save them to the device for easy "Add to Calendar" functionality.
Extended WebView
with .ics
File Download Handling
WebView
with .ics
File Download Handlingimport SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
// Define the specific UIView subclass we are representing
typealias UIViewType = WKWebView
let urlString: String
func makeUIView(context: Context) -> WKWebView {
// ... shortened ...
}
func updateUIView(_ webView: WKWebView, context: Context) {
// ... shortened ...
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
// Coordinator
// Handles callbacks from the WKWebView
class Coordinator: NSObject, WKScriptMessageHandler, WKNavigationDelegate, WKUIDelegate {
// Reference back to the SwiftUI view
var parent: WebView
// Weak reference maybe better if lifecycle allows?
var webView: WKWebView?
init(_ parent: WebView) {
self.parent = parent
}
// WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "MessageFromLiSA" {
// Handle message from JavaScript
print("Received message from LiSA: \(message.body)")
// You could trigger actions in your SwiftUI view here if needed,
// e.g., using @State variables passed down or Combine publishers.
}
}
// Handle navigation actions that become downloads
func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = self
print("Download started for: \(navigationAction.request.url?.absoluteString ?? "Unknown URL")")
}
// File download in progress
func download(_ download: WKDownload, didReceive response: URLResponse) {
print("Downloading: \(response.suggestedFilename ?? "Unknown filename")")
}
// Handle file download completion
func download(_ download: WKDownload, didFinishWith location: URL) {
guard let suggestedFilename = download.response?.suggestedFilename else {
print("Unable to retrieve filename")
return
}
let fileManager = FileManager.default
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationURL = documentsDirectory.appendingPathComponent(suggestedFilename)
do {
// Move the file to a permanent location
try fileManager.moveItem(at: location, to: destinationURL)
print("File saved to: \(destinationURL)")
// Present options to open the `.ics` file
DispatchQueue.main.async {
let activityViewController = UIActivityViewController(activityItems: [destinationURL], applicationActivities: nil)
if let topController = UIApplication.shared.windows.first?.rootViewController {
topController.present(activityViewController, animated: true, completion: nil)
}
}
} catch {
print("Error saving file: \(error.localizedDescription)")
}
}
// Handle errors during file download
func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
print("Download failed: \(error.localizedDescription)")
}
}
}
Key Changes and Additions
WKDownloadDelegate
ImplementationAdded support for
.ics
file downloads using theWKDownloadDelegate
methods.Handles download progress, completion, and errors.
Move
.ics
File to Documents DirectorySaves the
.ics
file to the app'sDocuments
directory for user access.
Present
UIActivityViewController
Provides options to open or share the
.ics
file, e.g., opening it in the Calendar app
Backwards Compatibility for iOS 14+
Ensures the solution works on devices running iOS 14 or later.
Last updated