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
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let urlString: String
func makeUIView(context: Context) -> WKWebView {
let webViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.allowsInlineMediaPlayback = true
webViewConfiguration.preferences.isElementFullscreenEnabled = true
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
configuration.userContentController.add(context.coordinator, name: "MessageFromLiSA")
let webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
webView.navigationDelegate = context.coordinator
webView.uiDelegate = context.coordinator // For handling UI interactions like alerts
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
uiView.load(request)
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
// MARK: Coordinator Class
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate, WKDownloadDelegate, WKScriptMessageHandler {
// Handle messages from LiSA
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "MessageFromLiSA", let body = message.body as? String {
print("Received message from LiSA: \(body)")
// Handle the JSON message
}
}
// 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 Implementation
Added support for .ics file downloads using the WKDownloadDelegate methods.
Handles download progress, completion, and errors.
Move .ics File to Documents Directory
Saves the .ics file to the app's Documents 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.