「The Ultimate Guide to WKWebView」をSwiftUIで実装してみるの、
4つ目になります。
目次
シリーズ化していこうと思うので、全体の目次を置いておきます。
リンクが貼られていないタイトルは、記事作成中または未作成のものになります。
# | タイトル |
---|---|
01 |
Making a web view fill the screen (WebViewを画面に表示する) |
02 |
Loading remote content (リモートのコンテンツを読み込む) |
03 |
Loading local content (ローカルのコンテンツを読み込む) |
04 |
Loading HTML fragments (HTMLフラグメントの読み込み) |
05 |
Controlling which sites can be visited (訪問可能なサイトの制御) |
06 |
Opening a link in the external browser (外部ブラウザでリンクを開く) |
07 |
Monitoring page loads (ページの読み込みを監視する) |
08 |
Reading a web page’s title as it changes (Webページのタイトルの変化を読み取る) |
09 |
Reading pages the user has visited (ユーザーが閲覧したページを読み取る) |
10 |
Injecting JavaScript into a page (JavaScriptをページに注入する) |
11 |
Reading and deleting cookies (cookieの読み取りと削除) |
12 |
Providing a custom user agent (カスタムUser Agentを提供する) |
13 |
Showing custom UI (カスタムUIを表示する) |
14 | Snapshot part of the page (ページの一部のスナップショットを撮る) |
15 | Detecting data (データの探索) |
環境
【Xcode】13.1
【Swift】5.5
【iOS】15.0
【macOS】Big Sur バージョン 11.4
実現したいこと
今回やることは
TextFieldに入力した文字列を元にHTML文字列を作成して表示します。
TextFieldになんも入力されてない時は、「nothing」の文字列が入るようにしました。
I love nothingってちょっと悲しい感じだけど・・・
またHTMLは、アプリバンドル内にあるCSSを読み込んでいます。
Hacking with Swiftの例より少しだけ発展版になっています。
今回の成果物は、こんな感じになりました。
実現方法
まずWebViewです。
最初にinputText
を使って、HTML文字列を作成します。
次に、そのHTMLに適用するCSSをアプリバンドルから読み込み、loadHTMLString(_:baseURL:)
のbaseURL
に渡します。
ちなみにbaseURL
は
「HTML文字列の中にある、相対URLを解決する時に使用するURL」とのこと。
The base URL to use when the system resolves relative URLs within the HTML string.
今回のこのHTMLでは、<link rel="stylesheet" type="text/css" href="index.css">
とあるように、CSSを適用しますので
その相対URLを取得してbaseURL
に渡しているわけです。
import Foundation
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let inputText: String
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
let displayedText = inputText.isEmpty ? "nothing" : inputText
let html = """
<html>
<head>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<h1>Hello World!</h1>
<h2>I am kamimi. I love \(displayedText).</h2>
</body>
</html>
"""
guard let urlPath = Bundle.main.path(forResource: "index", ofType: "css") else {
return
}
let url = NSURL.fileURL(withPath: urlPath)
uiView.loadHTMLString(html, baseURL: url)
}
}
ちなみに適用したCSSはこれ。
h1タグはオレンジに、h2タグは青になります。
h1 {
color: orange;
font-size: 100px;
}
h2 {
color: blue;
font-size: 80px;
}
Hacking with Swiftの例では、あまりbaseURL
の使い方は説明されてなかったので、試しに使ってみました。
またその例では、このHTMLをただ表示しているだけだったのですが、
<html>
<body>
<h1>Hello, Swift!</h1>
</body>
</html>
loadHTMLString(_:baseURL:)
のAppleのドキュメントを見たところ、Discussionに
「例えば、アプリがプログラムで生成したHTMLコンテンツを読み込むために使う」
For example, you might use this method to load HTML content that your app generates programmatically.
とあったので、TextFieldに入力された文字列をHTML文字列の中に埋め込む、というそれっぽい方法でやってみました。
ちなみに、仕事でこのメソッドを使用した時は、
APIのレスポンスの一部がこんな感じのHTML文字列だったので、それをWebViewで表示したいというユースケースでした。
{
"content": "<html><body><h1>Hello, Swift!</h1></body></html>"
}
このHTML文字列の場合であれば、baseURL
はnil
で良さそうですね。
特に相対パス埋め込まれていませんし。
では次に、WebViewを表示するViewです。
TextFieldが1つと、WebViewを開くためのボタンが1つあります。
開いたWebViewは、左上に閉じるボタンをつけました。
import SwiftUI
struct ContentView: View {
@State private var isShownWebView = false
@State private var inputText = ""
var body: some View {
VStack {
TextField("", text: $inputText)
.border(.yellow)
.padding()
Button(action: {
isShownWebView.toggle()
}) {
Text("WebView開く")
}
}
.fullScreenCover(isPresented: $isShownWebView) {
webBaseView
}
}
}
private extension ContentView {
var webBaseView: some View {
NavigationView {
WebView(inputText: inputText)
.navigationBarItems(leading: closeButton)
}
}
var closeButton: some View {
Button(action: {
isShownWebView.toggle()
}) {
Text("閉じる")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
以上です。
コード全体はこちらにあげています。
どうでも良い個人的な話なのですが、
Swiftも書きながら、HTML、CSSも書いてーとか色々触るの楽しいですね。