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

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

  1. WKDownloadDelegate Implementation

    • Added support for .ics file downloads using the WKDownloadDelegate methods.

    • Handles download progress, completion, and errors.

  2. Move .ics File to Documents Directory

    • Saves the .ics file to the app's Documents directory for user access.

  3. Present UIActivityViewController

    • Provides options to open or share the .ics file, e.g., opening it in the Calendar app

  4. Backwards Compatibility for iOS 14+

    • Ensures the solution works on devices running iOS 14 or later.

Last updated