WKWebView load files from both Bundle and Document directory - ios

I am running a webapp using WKWebView which load content and assets (html, js, img, css...) from a Bundle directory called Web_Assets.
I proceed like this to load index.html, and set Web_assets as baseURL:
if let filePath = Bundle.main.path(forResource:"index", ofType:"html", inDirectory: "Web_Assets") {
let html = try String(contentsOfFile: filePath, encoding: .utf8)
webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL?.appendingPathComponent("Web_Assets"))
}
This works perfectly: index.html is loaded and Web_Assets serve as base path for other ressources without any problem.
I could also use the loadFileURL method which is equivalent (to my understanding).
BUT, now i'd like to use other ressources (video in my case) inside my WKWebView from the Document directory which is static and manageable via iTunes File Sharing, while of course keeping the present architecture as it is (Web assets inside Bundle directory).
For example my page index.html would load his style.css and other assets from Web_Assets and display an HTML5 video located in Document
Is it possible to do this ?
Ideas (which i don't know how to achieve):
Symlink of Document in Web_assets ?
Different baseURL for different file types in WKWebView ?
(route all requests to Web_Assets except for mp4 files requests which are routed to Document)
Thanks for your help !
EDIT 1:
Idea 1 is not possible since Bundle directories are read-only.
Document can't be symlinked in Web_assets.
I can't manage to symlink Web_assets into Document either (weird error).
So i decided for now to copy Web_assets inside Document on each boot, so my Document folder can act as baseURL with my videos and web assets altogether.
It's a bit dirty since all my web assets are now visible in my Document folder (but not modifiable since the folder is erased and copied from Bundle uppon App restart)

I finally end up as EDIT 1 and #ngbaanh suggested:
on viewDidLoad:
let filemgr = FileManager.default
docURL = filemgr.urls(for: .documentDirectory, in: .userDomainMask)[0]
destPath = docURL.path+"/www/"
sourcePath = Bundle.main.resourceURL!.appendingPathComponent("Web_Assets").path
//COPY Web_Assets content from Bundle to Documents/www
do {
try filemgr.removeItem(atPath: destPath)
} catch {
print("Error: \(error.localizedDescription)")
}
do {
try filemgr.copyItem(atPath: sourcePath, toPath: destPath)
} catch {
print("Error: \(error.localizedDescription)")
}
// Configure Webview
webView.navigationDelegate = self
webView.configuration.userContentController.add(self, name: "teleco")
do {
let baseURL = try filemgr.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = baseURL.appendingPathComponent("www/index.html")
self.loadFileURL(fileURL, allowingReadAccessTo: baseURL)
} catch {
print(error)
}
This way my baseURL is Documents/www/
So in my index.html i can include ressources like style.css
AND i can also access files in Documents/ by using relative path like ../video.mp4
So index.html and style.css are distributed via the Bundle, copied to Documents at runtime, which allows me to access Documents files too.
A bit twisted, but works great.
Downside: it exposes Web_assets files in user accessible Documents folder.
But they can't be altered since they are replaced on App start.

Related

Parse data from local JSON file outside application bundle

I am trying to parse data from a JSON file which was created from a .sh script that is executed via CLI prior to building/running the project.
The following snippet does not work since my file was created from the .sh script and never added to my application bundle.
func fetchDatadogClientId() -> String? {
guard let url = Bundle.main.url(forResource: "client_token_key", withExtension: "json"),
let data = try? Data(contentsOf: url),
let datadogResponse = try? JSONDecoder().decode(DatadogResponse.self, from: data)
else {
return nil
}
return datadogResponse.clientToken
}
Would there be a way to read from this JSON file outside the application bundle or perhaps add the file to the project bundle using a script that would be run during the Build Phases?
Any suggestions are appreciated. Thanks in advance.

How to get resource path for PNG files from Bundle?

I'm trying to get a resource path of image files added to the project. The following code works fine for jpeg files. But it gives nil for PNG files. The name of the images are correct and added to the project.
Image files are added with the puppy.png and car.jpeg names.
let carPathURL = Bundle.main.path(forResource: "car", ofType: "jpeg") // Gives right path
let puppyPathURL = Bundle.main.path(forResource: "puppy", ofType: "png") // Gives nil
Below is the screenshot of the Application bundle contents.
The screenshot for the project is below showing the added files.
Why it is giving nil for PNG files? How to get the resource path for PNG files?
If extension is uppercased (ie, PNG, not png) you have to specify this explicitly
Bundle.main.path(forResource: "puppy", ofType: "PNG")

pathForResource returns nil

I have two files, both named GoogleService-Info.plist. One is inside the folders Resources -> Staging and another is in the folders Resources -> Production. They're both added to Copy Bundle Resources. My code to access one of them is this:
if let path = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist", inDirectory: "Resources/Staging") {
print("this should work but doesn't")
}
It always returns nil. Why can it not find the file?
The resources will be put in the root of your app bundle. The only time you will get folders inside your app bundle is when you create folder references in your project. These will be blue folders, not yellow.
Change your code to (remove the inDirectory part):
if let path = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist") {
print("this should work but doesn't")
}

Read file in Xcode project with Swift

I made a method to read a file from the temporary folder. I use the following lines to get the document's path:
path = NSTemporaryDirectory().stringByAppendingPathComponent(folder)
path = path.stringByAppendingPathComponent(fileName + "." + fileType)
And it works great. My question is: how do I get the path for a file located in the main folders of the Xcode project? They are two text files that I drag and drop from a folder to the Xcode project. I selected the option "copy files if needed" when dropping the files. Thanks!
What you are looking for is app's main bundle. You get a path of a file in it like this:
if let path = NSBundle.mainBundle().pathForResource(fileName, ofType:fileType) {
// use path
}
Keep in mind this folder is read-only so you will need to copy the files to temp or documents folders if you want to make changes.
Update the Swift 3.1 - Thanks #Filip Radelic
if let path = Bundle.main.path(forResource: fileName, ofType: fileType) {
// use path
print(path)
}
Swift 4
if let path = Bundle.main.path(forResource: "imagename.png", ofType: nil) {
print("[check] FILE AVAILABLE \(path)")
}
You would use NSBundle to get your main bundle, then pathForResource(_ name: String?, ofType extension: String?) -> String?.

HTML does not respect .CSS file in UIWebView

I am trying to load html page in WKWebView which is linked to external javascript and css files. My web view shows me the html page but it does not seem like that its respecting css file values. Can anyone please suggest me as to what am I doing wrong here. Following my code to add html page in WKWebView:
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html");
let htmlString = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil);
self.webView.loadHTMLString(htmlString, baseURL: NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath));
}
Also, here is the project structure where .css, .js and .html files re added.
Any help would be appreciated.
The problem is that the WKWebView renders page content inside a sandbox process that cannot access files in your application bundle. This effectively means that file:// URLs do not work.
I ended up including a small web server in my application to make it easier to serve content to the WKWebView.

Resources