WKWebView intercept local file requests - ios

I have a WKWebView in my iOS 11+ app where I need to load custom HTML from local in-memory HTML. I can accomplish this by using webView.loadHTMLString or webview.load(data), which is working fine.
This HTML references some required .js/.css/.png files. For normal web URL requests, WKWebView will just do this on the fly, loading missing files. But in this case, I need to intercept these requests, and provide the file contents, as some of it needs to be dynamically generated. So the .css files etc. I need to serve are not physically present as local files.
I thought this would be just a matter of implementing the decidePolicyFor methods of the WKNavigationDelegate protocol, but for some reason this is not triggered for local subrequests, so how can I accomplish this?
I also tried saving the HTML as a local temporary file and loading it using webView.load(URLRequest), but that does not trigger the delegate either. If it was a web URL, it triggers fine.

Let's say you render fullIosAppPath/page.html which has text like <img src="folder/1.png">.
In such case you need to have a file fullIosAppPath/folder/1.png in your app's folder. The WKWebView will load 1.png without any interception - it will just render the image.
So you can parse the HTML file before rendering it, and generate/load the requires resources like 1.png.
You can parse an HTML file with frameworks like Kanna, or write some simple parser by yourself.

Related

How to download from Apple's QuickLook link scheme "x-apple-ql-magic"?

TL;DR - I want to download a .csv and other files from a link, and present a UIActivityViewController.
I'm working in an app with lots of WKWebViews. In one of the delegate methods, decidePolicyForNavigationAction:, the available URL is a URL compatible with URLRequests, and I can download just fine from it. (navigationAction.request.url)
In another delegate method decidePolicyForNavigationResponse: the response's url (navigationResponse.response.url) identifies as part of Apple's QuickLook framework scheme, and contains this: x-apple-ql-magic. I was trying to use a QLPreviewController, but couldn't populate the dataSource with a remote file I wanted to download.
My goal is: When a link points to a downloadable file, like a .csv or PDF, give a user the option to share this file via UIActivityViewController.
How can I download remote files from this scheme: x-apple-ql-magic?
You can’t. When WKWebView previews a file such as CSV, it is internally converted to HTML by Quick Look to be rendered by WebKit. The x-apple URL is the URL of the converted content. It should not be exposed to you, you should be seeing the original URL instead, please file a bug.
Why do you want to use the response delegate in the first place instead of the delegate at link tap time?

Use Dynamic Javascript in iOS Share Extension

I am developing a share extension for iOS 8 and it seem like i can run javascript code on page to grab some information like markup of the mage
But on the apple document it says that javascript code must be inside a .js file but my javascript code is coming from server and it is dynamic.
Is it possible to run javascript i downloaded from server or can I change js file contents everytime I need to use it?
You can't do this using the built-in support in the current share extension system.
The Javascript file needs to be listed by name in the extension's Info.plist, in the value of the NSExtensionJavaScriptPreprocessingFile key. The file named there needs to exist in the app extension's bundle. But bundles are not writeable, so you can't replace or change the file.
You might be able to do something like you describe if you:
Include a basic JS file that just returns the entire page source to your extension.
Use JavaScriptCore.framework to further process that data in your extension.
I don't know of any reason why that wouldn't work, but I haven't tried it, and it's kind of unusual. Still, given your needs, it's worth investigating.

UIwebview loading remote html with bundle/local images

Well, i searched everywhere but i didn't have any luck with my situation.
I am loading my webpage with UIWebView with the following code:
NSString *fullURL;
fullURL=#"http://domain.com";
NSURL *url=[NSURL URLWithString:fullURL];
NSURLRequest *requestObj=[NSURLRequest requestWithURL:url];
[_webView loadRequest:requestObj];
I want to load the remote HTML file but load the images from the bundle resourses.
The HTML file looks like this:
<img src="http://domain.com/images/image.png" width="20px" height="20px"/>
Can this be done? The majority of the posts over the internet(and here) are for loading local HTML with local images/resources which is different in my case.
Any help with my code?
Thanks
It would probably be better to use some more "loosely coupled" solution - not to edit the HTML code itself in some hacky way (regexp, not regexp... changing the HTML code manually is still pretty hacky).
As a matter of fact, I believe it can be done. The iOS just needs to be somehow informed that some of the assets are available offline, from the bundle.
Basically, when UIWebView is loading a page, first thing that happens behind the scene is downloading the main *.html page. Then all the graphics/css'es/js'es etc are being downloaded.
You can let the html file be downloaded "as is", but intercept those requests that are going to download graphics (+ other assets) and provide them from local bundle. Please refer to this post:
http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588
and apply appropriate changes. The big win here is that from the webview's (and code that loads / maintain via JavaScript calls it's content) perspective - nothing has changed at all. Only the custom NSURLProtocol itself knows that some data was loaded from local storage.
Had the exact same problem. Subclassing NSURLCache to redirect the cache to cache images from local storage worked like a charm.
Here is the writeup that I followed:
http://www.cocoawithlove.com/2010/09/substituting-local-data-for-remote.html
TL;DR Complicated, avoid if you can, but possible.
If you still want to do it: don't do a UIWebView :loadRequest on the URL itself since it will trigger the start of downloading images very rapidly so modifying the images sources using Javascript will likely happen too late.
What you instead have would have to do is to download the contents of the URL on the native side and iterate the image tags there replacing the sources (quite complicated, don't use Regular Expressions to parse HTML btw, there are libraries for that), then injecting the modified HTML using UIWebView loadHTMLString:baseURL:.

iOS - Download files to application folder

I do have a UIWebview inside one of my UIViewControllers. The destination URL to be displayed within the WebView is a page on my server (therefore I have access to make changes on it).
That page basically has a list of PDFs to be downloaded (imagine an un-ordered list of hyperlinks each pointing to a PDF file).
I need a way to tell my App that whenever a file is downloaded from that WebView by clicking on one of the links, I need it to be saved inside my application folder instead of the iPhone/iPad memory.
Is there any way I can achieve that? Are there alternatives?
You can allow UIWebView to call your Objective-C delegate function. This link provides an overview of how to do it: http://dblog.com.au/iphone-development/iphone-sdk-tip-firing-custom-events-when-a-link-is-clicked-in-a-uiwebview/ Basically, the delegate function will be called on all requests from the UIWebView. You can examine if they are for links to a pdf files, and if so, write your own objective-c code to download the file and store it in your Application directory. You'll probably want to add some UI to let the user know what is happening. Otherwise you let the request go on as normal and it will be displayed in the web browser.

I cannot get the StageWebViewBridge to load external assets

I am using appfile:/. The path is correct; if I put it on screen and copy-paste it in the explorer it links to the image.
Is there anything else I need to do?
UPDATED I have updated the library, now is more easy to use. Can you test it?
I am the author of the StageWebViewBridge class. There is a known problem if you are using Android. Anyway, I have a working solution I will update the next week.
If the problem is not in Android, then send me some code.
I am also confused on how to access locally packaged assets. I put them in the HTML folder as requested and when I send a signal to the StageWebViewBridge to set the .src attribute of a video I'm not sure how to do it.
Without StageWebViewBridge and entirely in a website I can just reference the file for a video object via JavaScript directly e.g. swvRef.src = 'file.mp4';. This works perfectly fine. When I try to tell flash to send a call via StageWebViewBridge it does receive the call to the StageWebView (I have JavaScript reporting it). However when I try to set the .src of a video object I can't figure out the correct path.
The documentation says to put all things in a 'html' folder. I did so. No reference to a .src of 'html/a.mp4' or 'a.mp4' or 'htmlCache/a.mp4' ever makes the new javascript html5 video class work.
Bridge otherwise is working perfectly sending AS->JS and JS->AS. I'm just looking for info on how to reference packaged files. I want to play a video I put in the /html folder and so far, I just can't do it.
Got the same issue and fixed it with "appfile:/"
Why do you require "appfile:/ for a local html file ?
If the treated html/js/css is local and asset is relative (aka ../ or no http://) you should treat them as "appfile:/" ?
If the treated file is distant you do not have to handle assets ?
Is there a best practice to work with "appfile:/" ?
Actually I debug my html/js/css game in the browser but if I use appfile:/ it will no longer works. I will have to handle 2 behaviors.

Resources