web-dev-qa-db-ja.com

WKWebViewはローカルドキュメントフォルダからリソースをロードします

私のSwift iOSアプリでは、リモートサーバーからいくつかの動的なHTMLページをダウンロードし、ドキュメントディレクトリに保存し、ドキュメントディレクトリからそれらのページを表示します。

私はこれを使用してページをロードしていました:

var appWebView:WKWebView?
...
appWebView!.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath: htmlPath)))

すべてがシミュレーターで機能しますが、実際の電話に移動すると、空白のページが表示されました。次に、Safariを使用してアプリに接続しましたが、「リソースの読み込みに失敗しました」という苦情が見つかりました。

次に、最初にhtmlPathのページのコンテンツを読み取ってから、

appWebView!.loadHTMLString()

ページをロードします。 HTMLページが単純な場合に機能します。ただし、HTMLが他の何かを参照する場合、つまり、ドキュメントディレクトリ内のJavaScriptファイル(<script src="file:////var/mobile/Containers/Data/Application/762035C9-2BF2-4CDD-B5B1-574A0E2B0728/Documents/xxxxx.js">)、ロードに失敗します。

なぜこれが起こるのか、問題を解決する方法を知っていますか?

詳細:

  • XCodeバージョン:7.3.1
  • 展開ターゲット:8.1(9.3も使用しようとしましたが、助けにはなりませんでした。)
28
Peter

これは、私のプロジェクト(iOS 10、Swift 3))でローカルファイルをロードするために使用したものの簡易バージョンです。コメントでRaghuramとFox5150が要求したとおり、iOS 10.3.1およびiPhone 7以降で再度テストした後、コード(7.5.2017).

完全に新しいプロジェクトを作成しましたが、これはフォルダー構造です: enter image description here

2018年4月19日更新:HTML、CSS、JSファイルを含む.Zipをダウンロードし、/ Documents /(Alamofire + Zip )そしてそれらのファイルをwebViewにロードします。 GitHubサンプルプロジェクト にもあります。繰り返しますが、フォークとスターをお気軽に! :)

アップデート08.02.2018:最後に GitHubサンプルプロジェクト を追加しました。これにはローカルJavaScriptファイルも含まれています。分岐とスターをお気軽に! :)

WebView.loadFileURL()を使用したバージョン1

ViewController.Swift

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let webView = WKWebView()
        let htmlPath = Bundle.main.path(forResource: "index", ofType: "html")
        let htmlUrl = URL(fileURLWithPath: htmlPath!, isDirectory: false)
        webView.loadFileURL(htmlUrl, allowingReadAccessTo: htmlUrl)
        webView.navigationDelegate = self
        view = webView
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

WebView.loadHTMLString()を使用したバージョン2

ViewController.Swift

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let webView = WKWebView()
        let htmlPath = Bundle.main.path(forResource: "index", ofType: "html")
        let folderPath = Bundle.main.bundlePath
        let baseUrl = URL(fileURLWithPath: folderPath, isDirectory: true)
        do {
            let htmlString = try NSString(contentsOfFile: htmlPath!, encoding: String.Encoding.utf8.rawValue)
             webView.loadHTMLString(htmlString as String, baseURL: baseUrl)
        } catch {
            // catch error
        }
        webView.navigationDelegate = self
        view = webView
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

気をつけるべきゴチャ:

  • ローカルのhtml/js/cssファイルがProject-> Target-> Build Phases-> Copy Bundle Resourcesにあることを確認してください
  • HTMLファイルが相対パスを参照していないことを確認してください。 css/styles.css iOSはファイル構造をフラット化し、styles.cssはindex.htmlと同じレベルになるため、<link rel="stylesheet" type="text/css" href="styles.css">代わりに

2つのバージョンとここでの落とし穴は、プロジェクトからの私のhtml/cssファイルです:

web/index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    <title>Offline WebKit</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
  </head>
  <body>
    <h1 id="webkit-h1">Offline WebKit!</h1>
  </body>
</html>

web/css/styles.css

#webkit-h1 {
  font-size: 80px;
  color: lightblue;
}

誰かがGitHubサンプルプロジェクトを希望する場合は、コメントセクションで教えてください。アップロードします。

32
tech4242

Swift 4メソッド

このメソッドにより、WKWebViewは、リンクされたCSS/JSファイルのディレクトリおよびサブディレクトリの階層を適切に読み取ることができます。 HTML、CSS、またはJSコードを変更する必要があります[〜#〜] not [〜#〜].

Xcode 9.3用に更新されました

ステップ1

ローカルWebファイルのフォルダーをプロジェクトの任意の場所にインポートします。次のことを確認してください。

Xcode > File > Add Files to "Project"

needed️必要に応じてアイテムをコピーする

☑️フォルダー参照の作成(「グループの作成」ではない)

targets️ターゲットに追加

ステップ2

WKWebViewを使用してView Controllerに移動し、次のコードをviewDidLoadメソッドに追加します。

let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
  • index –ロードするファイルの名前(.html拡張子なし)
  • website – Webフォルダの名前(index.htmlはこのディレクトリのルートにある必要があります)

結論

全体的なコードは次のようになります。

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.uiDelegate = self
        webView.navigationDelegate = self

        let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "Website")!
        webView.loadFileURL(url, allowingReadAccessTo: url)
        let request = URLRequest(url: url)
        webView.load(request)
    }

}

このメソッドまたはコードについてさらに質問がある場合は、できる限りお答えします。 :)

11
Matt Swift

このソリューションは私を助けました:

[configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];

これはうまく機能します(Swift 3、Xcode 8):

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

    var webView: WKWebView!

    override func loadView() {
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        if let url = Bundle.main.url(forResource: "file", withExtension: "txt")
        {
            do
            {
                let contents = try String(contentsOfFile: url.path)
                webView.loadHTMLString(contents, baseURL: url.deletingLastPathComponent())
            }
            catch
            {
                print("Could not load the HTML string.")
            }
        }
    }
}
1
hkdalex

これは、ファイルURLまたはリモートURL、およびファイルがバンドル内にあるかドキュメント内にあるかでうまく機能します。

if url.isFileURL {
    webView.loadFileURL(url, allowingReadAccessTo: url)
} else {
    let request = URLRequest(url: url)
    webView.load(request)
}
1
drewster