Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@utwang

SwiftからJavascript(Ajax)で利用する認証情報を設定する

iOSのアプリ開発において、一部の機能についてはWebviewを利用してHTMLをする画面を作る際、単純なHTMLの表示だけではなくJavascriptで非同期にデータを取得して、HTMLをレンダリングすることもあります。
もし、アプリ-サーバ間でユーザ認証を行っている場合、次のタイミングでサーバ側に認証情報を送る必要があります。
1. HTML取得時(HTTPリクエストによる同期通信)
2. 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で利用する場合

jQuery
$.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などを利用している場合は、こちらを利用するケースが多いでしょうか)

whatwg-fetch

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)
    }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
10
Help us understand the problem. What are the problem?