Downloading files in a Web View since iOS 15 has never been easier

Mohamed ARRADI ALAOUI
6 min readOct 22, 2021
Image from Photo by Caspar Camille Rubin on Unsplash

Web Views are greats for a lot of purposes, as an native mobile developer whether we like it or not, we always need to display some static web content (FAQs, Terms and Conditions, Legal, etc..) that does not harm the native experience.

For many companies still, whether it is because of lack of tech resources or cost, running a mobile website version inside an web view and ship it to the store, is the quickest and cheapest solution to step into the mobile app world and leverage the app stores legendary marketing power.

However, from my personal experiences, a common assumption that I always foresee, is that everyone expect the mobile web version embedded into the web view to work as it works on Safari or Google Chrome. This is due because web views are deeply considered as embedded mini-browsers.. reality is a bit different.

Web Views are not pure browsers, they use the core engine let’s say !

Therefore some capabilities will not be present in the web view out of the box. As a history, web views were initially planned just to display local static web pages within the app. The capability that web developers expect the most to not being there is: downloading documents (PDF, CSV file, etc) on the iOS file system.

This capability was never supported easily and required quite extra efforts and required to handle few mime-types only. Then whenever the web view was able to display a file, it was usually breaking the web navigation as most file download are used under a target=_blank action which break navigation history. Therefore it forced users to kill the app, terrible experience..

iOS 15 just made download and display document easier.

Part 1: Download File in iOS file system

Before iOS 15 there were couple of solutions that we won’t develop much here but the most common solution was to play around the mime-type response of a web request and then surcharge a download request if mime-type was kind of a document type and not html/text.

During WWDC 2021, Apple announced couple of new changes in this video. Improvements goes from better JavaScript execution, enhanced media player control and much much more. Today we will explain a delegate named WKDownloadDelegate

The documentation is still a bit scarce but we will go through it. First of all, we will need to add this few delegates in our class or controller that hold the WKNavigationDelegate as per below.

As you can see, the entire responsibility of whether we should prepare a download or a web page loading is solely handled by the shouldPerformDownload property.

Please ignore the canShowMimeType property for now we will come to it later at the second part.

So what shouldPerformDownload does exactly ?

iOS 15 — WKWebView Download Delegate

Well, It simply leverage a very interesting HTML attribute and not very often used which is meant for signaling that a HTML link is responsible for a download (more detail over there).

So simply by adding a download attribute in your web link will do the trick !

When the web view will encounter any links with the download attribute it will not try to load the link as a web page request but as a download request.

Unfortunately this HTML attribute just express an intent to download not the execution, we still have a bit of work for the download to happen, and few delegates will come now into play.

  • 2 are mandatory.
  • 2 are optional but recommended if you need to react on the UI side (success/failure).

Something I would like to stress out here is that the delegate is not a WKWebView delegate so it won’t be retained by the web view. It is then very important to keep a reference of it. The most important delegate is the first one which define where the file will be saved once downloaded.

I strongly advise to keep a reference of the file path before passing it toward the completion block if you would to access it later on the success or error delegate. The success delegate does not return you the file path unfortunately.

I do not know if you noticed but a very nice thing about this delegate is the suggested filename as a parameter.

So there is no extra effort to generate any random filename while creating the file path, you can just match what the web server gives you. Less work the better right !

Once the completion block executed, the download will then start and you will receive either a success or a failure callback if download succeed or not.

Something worth noticing here is the error delegate below:

As you can see it gives us an additional resumeData object, but why ?

Well, like your desktop browser when a download got stopped in the middle usually you have the ability to resume it unless servers does not allow it.

This capability is now given to the WebView too and this can be very useful for very long download, especially on mobile networks.

Part 2: Displaying file without breaking navigation

A bit earlier, I asked you to forget the canShowMimeType property from the WKNavigationDelegate. Now it is time to dig into it.

This property helps to resolve an issue that most of iOS developers had encountered with Web Views at least couple of times.

Indeed sometimes your Web View is able to download the document but displays it directly within the main web frame. That’s seems great but if your link was under a “target=_blank” then it makes it impossible to go back as the web navigation is now broken..

Unlike android we do not have a native back button, so most of the time the user has to kill the app and this could happen at the worst possible moment.. This is what this property does.

If the Web View can present the document without breaking the web navigation it will do it, otherwise it will download it.

This is a definitely a savior !

We have now just covered almost everything which is related to downloading or displaying files safely within the Web View and we can definitely understand the benefits that this API is bringing to us, but unfortunately this is great for apps that will start with iOS 15 as a minimum deployment target.

For others we have to be pragmatic. We will still need to handle the old way as a fallback for the next coming 1 or 2 iOS releases. Most companies still ask to support N-2 versions.. and if your company is Facebook then you will likely retire before having only iOS 15 implementation 😛.

I hope this article helped to grasp a good overview of the WKDownloadDelegate and what this new API brings to the table for iOS developers that need to handle some web content within their apps.

There are other things to cover but are more for very specific cases (HTTPS redirection handling, request challenges, etc).

I will allow myself a bit of criticism I would say that there is only one crucial API missing in my opinion: a download progress delegate.

Indeed as we discovered above, we can just be notified if a download succeeded or failed, but what if we would like to display a progress for a larger and longer download ? Maybe this will come in the future and that would be very appreciated.

On a last note, as I mentioned a bit earlier, in order to facilitate the download and delegation system, a separate object model could be really useful. Here is one simple example below.

Thank you for reading it, no it is time to code on your side :)

--

--