4

Using WKWebview for playing local file works on simulator but give me this error on device (iOS 9.2.1)

fail in didFailProvisionalNavigation Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"
UserInfo={NSErrorFailingURLKey=file:///var/mobile/Containers/Data/Application/2FBE4DE6-9441-4C5A-BB1F-8598CA89664C/Documents/courses/agdg_test1455704820291/index.html?jqueryFilePath=file:///var/mobile/Containers/Bundle/Application/5A442D34-3360-46C7-8B28-B6F3AED373CE/elearning.app/view/jquery.js&commandsFilePath=file:///var/mobile/Containers/Bundle/Application/5A442D34-3360-46C7-8B28-B6F3AED373CE/elearning.app/view/commands.js,
_WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x15e295f0>,NSErrorFailingURLStringKey=file:///var/mobile/Containers/Data/Application/2FBE4DE6-9441-4C5A-BB1F-8598CA89664C/Documents/courses/agdg_test1455704820291/index.html?jqueryFilePath=file:///var/mobile/Containers/Bundle/Application/5A442D34-3360-46C7-8B28-B6F3AED373CE/elearning.app/view/jquery.js&commandsFilePath=file:///var/mobile/Containers/Bundle/Application/5A442D34-3360-46C7-8B28-B6F3AED373CE/elearning.app/view/commands.js}

Here is code provisioning the webView :

let lesson:NSMutableArray = courseDB_Manager.getInstance().getRowDB("SELECT * FROM lesson_chapter WHERE lesson_chapter_id = ?", args: [chapterToPlay], structType: "lesson_chapter")
let occ: lesson_chapter_struct = lesson[0] as! lesson_chapter_struct
fileToPlay = Utility.getPath("courses/" + occ.lesson_chapter_fichier)

let commandsFilePath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("commands", ofType: "js", inDirectory: "view")!, isDirectory: false)
let jqueryFilePath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("jquery", ofType: "js", inDirectory: "view")!, isDirectory: false)

let target = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("start", ofType: "html", inDirectory: "view")!, isDirectory: false)
let params = "?fileToPlay=" + fileToPlay + "&commandsFilePath=" + String(commandsFilePath) + "&jqueryFilePath=" + String(jqueryFilePath) + "&" + NSUUID().UUIDString
let url = NSURL(string: NSString(string: target.absoluteString + params) as String)
NSURLCache.sharedURLCache().removeAllCachedResponses()
NSURLCache.sharedURLCache().diskCapacity = 0

if(progress.current() != 1) {
    let askForResume = UIAlertController(title: "Resume", message: "Resume ????????????", preferredStyle: UIAlertControllerStyle.Alert)
    askForResume.addAction(UIAlertAction(title: "YES", style: .Default, handler: { (action: UIAlertAction!) in
        self.resume = true
        self.webView.loadFileURL(url!, allowingReadAccessToURL: url!)
    }))
    askForResume.addAction(UIAlertAction(title: "NO", style: .Default, handler: { (action: UIAlertAction!) in
        self.webView.loadFileURL(url!, allowingReadAccessToURL: url!)
    }))
    presentViewController(askForResume, animated: true, completion: nil)
} else {
    self.webView.loadFileURL(url!, allowingReadAccessToURL: url!)
}

After implementing allowingReadAccessToURL i've got this error :

Received an unexpected URL from the web process: 'file:///[...]commands.js'
Received an invalid message "WebPageProxy.DecidePolicyForNavigationAction" from the web process.

it is because, files requested by js are confronted to same issue ?

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
    decisionHandler(WKNavigationActionPolicy.Allow)
}

UPDATE 1 - Resolved in second update

Now, i'm using this code :

let target = NSURL(fileURLWithPath: fileToPlay + "/index.html", isDirectory: false)
let params = "?commandsFilePath=" + String(commandsFilePath) + "&jqueryFilePath=" + String(jqueryFilePath) + "&" + NSUUID().UUIDString
let url = NSURL(string: NSString(string: target.absoluteString + params) as String)

if #available(iOS 9.0, *) {
    self.webView.loadFileURL(url!, allowingReadAccessToURL: url!)
} else {
    do {
        let fileUrl = try self.fileURLForBuggyWKWebView8(url!)
        self.webView.loadRequest(NSURLRequest(URL: fileUrl))
    } catch let error as NSError {
        print("Error: " + error.debugDescription)
    }
}

Whose work fine on simulator (iOS 9), namely, load fileUrl and files included by js code. But on device (also iOS 9), it's load fileUrl and js files included from mainBundle but not js files in same directory of fileUrl

e.g : fileUrl points to

"file:///var/mobile/Containers/Data/Application/4F2A96AF-8E58-41A6-A4D3-A19D254C048F/Documents/courses/agdg_test1455704820291/index.html"

including js files from subdirectory of fileUrl doesn't work

"file:///var/mobile/Containers/Data/Application/4F2A96AF-8E58-41A6-A4D3-A19D254C048F/Documents/courses/agdg_test1455704820291/data/player.js"

But including js files from bundle work's perfectly. I also verified with iPad File Explorer that file /data/player.js exist and it's the case.

UPDATE 2

I resolved this with set allowingReadAccessToURL to entire directory, not only my index file.

Since i use this method for provisioning WKWebView, js code is never finish to buffering sounds/videos to play on device...I don't understand who's the difference that make execution so slow between -[WKWebView loadFileURL:allowingReadAccessToURL:] and [WKWebView loadRequest]

Khorwin
  • 445
  • 1
  • 9
  • 27
  • Where is this "local file"? Did you add it as a resource to your project, or is it on your computer? – wottle Mar 07 '16 at 15:43
  • No, it's download by the app inside app documents. App work fine with UIWebView on device (but so slow to execute my js player) with exactly the same files, but only work in simulator with WKWebView. I edit my question to give all returned error. – Khorwin Mar 07 '16 at 15:56
  • Please add your code for how you load the data. Also, iOS 9? In iOS 8, you cannot load from a file URL in WKWebView. – wottle Mar 07 '16 at 16:01
  • Take a look at my answer. You cannot load a local file in that way in WKWebView. – wottle Mar 07 '16 at 16:07

1 Answers1

9

In iOS 9 and up, WKWebView has a new method that will do what you want, -[WKWebView loadFileURL:allowingReadAccessToURL:]

Make sure you are loading the local resource with that call.

If you are supporting iOS 8, it get s a little more difficult. See this answer for more details.

Community
  • 1
  • 1
wottle
  • 13,095
  • 4
  • 27
  • 68
  • 1
    FYI, iOS 8 support caused me to have to use a UIWebview in our app. The benefits of WKWebView didn't justify the work / risk of the workarounds. – wottle Mar 07 '16 at 16:10
  • I develop an offline e learning using our player in js, on Android and UWP webviews work's fine but too long on UIWebView (buffering on buffering) so WKWebView seem to run fine on simulator. I edit my question to add new problem – Khorwin Mar 07 '16 at 16:41
  • Your code is using `[WKWebView loadRequest:]`. Have you tried loadFileURL as I mention in my answer? – wottle Mar 07 '16 at 18:17