iOSのアプリ開発において、一部の機能についてはWebviewを利用してHTMLをする画面を作る際、単純なHTMLの表示だけではなくJavascriptで非同期にデータを取得して、HTMLをレンダリングすることもあります。
もし、アプリ-サーバ間でユーザ認証を行っている場合、次のタイミングでサーバ側に認証情報を送る必要があります。
- HTML取得時(HTTPリクエストによる同期通信)
- Javascriptコード内での非同期通信
今回、iOSネイティブ側からWebviewのJavascriptへ認証情報を渡す方法をまとめます。
前提として
- iOSネイティブ側で認証情報を
既に保持している
- WebviewはWKWebViewを使用する
- 認証情報はヘッダー情報にtokenとして設定する
動作環境
- Xcode 8.1
- Swift 3.0.1
HTML取得時に認証情報を設定する
WKWebViewのloadで送信するURLRequestのヘッダー情報にtoken情報を設定するだけです。
let token = `token情報`
guard let url = URL(string: `エントリポイントのURL`) else { return }
let request = URLRequest(url: url)
request.addValue(token, forHTTPHeaderField: "Auth-Token")
webView.load(request)
SwiftからWkWebViewのJavascriptに認証情報を渡す
HTMLの読込後に実行されるJavascript内で非同期でデータ取得を行う場合は、実行前に認証情報を設定しておく必要があります。
①DOM構築 -> ②アプリケーションスクリプト実行
②より前のタイミングでSwiftからJavascriptへ認証情報を渡す必要がある
iOS側のコードは次のようになります。
let token = `token情報`
let jsSrc = "AppConfig = {}; AppConfig.authToken = '\(token)';"
let script = WKUserScript(source: jsSrc, injectionTime: .atDocumentStart, forMainFrameOnly: true)
webView.configuration.userContentController.addUserScript(script)
ポイントはWKUserScriptで指定するinjectionTimeにWKUserScriptInjectionTime.atDocumentStart
を設定すること。
この設定によりWKWebViewがDOMを生成した直後に、指定したスクリプトを実行してくれます(他のコンテンツをロードする前に実行されます)
injectionTimeにWKUserScriptInjectionTime.atDocumentEnd
を指定した場合、スクリプトの実行や、他のコンテンツの読込が終わった後にWKUserScriptで定義したjavasriptが実行されるため、認証情報がないまま非同期通信を行うことになります。最後にHTMLを更新する場合などに適しています。
javascript側の利用例
ネイティブ側から渡された認証情報をJavascript側から利用する例です。
jQuery Ajaxで利用する場合
$.ajax({
url: `APIのエンドポイント`,
type: 'GET',
dataType: 'json',
headers: {
'Auth-Token': AppConfig.authToken
}
success: function(res, status, xhr) {
// do something
}
error: (xhr, status, error) {
// do something
}
})
fetch APIを利用する場合(ES6などを利用している場合は、こちらを利用するケースが多いでしょうか)
fetch(`APIのエンドポイント`, {
headers: {
'Auth-Token': AppConfig.authToken
}
})
.then(response =>
// do something
)
iOS側のコード最終形
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var webview: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Javascript内のAjaxで利用するための設定
let token = `token情報`
let jsSrc = "AppConfig = {}; AppConfig.authToken = '\(token)';"
let script = WKUserScript(source: jsSrc, injectionTime: .AtDocumentStart, forMainFrameOnly: true)
webView.configuration.userContentController.addUserScript(script)
// HTML取得時の認証情報設定
guard let url = URL(string: `エントリポイントのURL`) else { return }
let request = URLRequest(url: url)
request.addValue(token, forHTTPHeaderField: "Auth-Token")
webView.load(request)
}
}