2024/09/23 Updated by

Swift 5

Webサーバにアクセスする (URLSesstion)


[Up] Japanese English
  1. 開発環境
  2. Webサーバ
  3. mac で Xcode を起動する
  4. 新しいプロジェクトを開始する。
  5.   プラットホーム: iOS
      Application: App
    

  6. プロジェクトのオプションを選択する。
  7. あとで、デバイス上で動作させるためには、Team: を (Personal Team) に設定する。

  8. Xcode のウィンドウ左の Project Navigator で Main.storyboard を選択する。


  9. 真ん中のウィンドウの上の「+」(Show Library)をクリックして、Object ウィンドウを表示する。

  10. Objct ウィンドウから Button をドラッグして、ViewController の画面上に配置する。

  11. 真ん中のウィンドウの上の「5本の横棒」(Adjust Editor Options)アイコンをクリックして、メニューから Assistant を選択する。

  12. 真ん中のウィンドウが2つに分割されて、ViewController の画面と ViewController.swift が表示される。

  13. 「ViewController の画面」上で Button をクリックして選択し、キーボードのControlキーを押しながら Button をドラッグし、 ViewController.swift の「クラス内、関数定義外、なるべく上部」の位置に配置する。

  14. Connection を Action に変更し、わかりやすい関数名を指定する。ここでは "tapButton" とした。

  15. ViewController.swift の中に @IBAction と指定された関数 tapButton() のコードが挿入される。 この関数は「ViewController 画面」の上の Button がクリックされた時に呼び出される。

  16. 関数 tapButton() の中に、URLSession を使って Web アクセスするコードを追加する。

  17. ViewController.swift
    //
    //  ViewController.swift
    //  URLSession
    //
    //  Created by Yoshihisa Nitta on 2024/09/23.
    //
    
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBAction func tapButton(_ sender: Any) {
            let url = URL(string: "http://localhost:8080")!
             let request = URLRequest(url: url)
             let session = URLSession.shared
             session.dataTask(with: request) { (data, response, error) in
                 if error == nil, let data = data, let response = response as? HTTPURLResponse {
                     print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                     print("statusCode: \(response.statusCode)")
                     let s = String(data: data, encoding: String.Encoding.utf8) ?? ""
                     print(s)
                     //self.myLabel.text = s
                 }
             }.resume()
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    
    
    }
    
    
  18. 真ん中ウィンドウを上部の「デバイスやシミュレータを選択する」メニューから、適切なシミュレータを選ぶ。ここでは iPhone16 シミュレータを選択した。

  19. 上部から実行ボタン をクリックする。

  20. iOS シミューレータが起動する。

  21. シミューレータ画面上の Button をクリックすると、Webサーバにアクセスする。
  22. 同一マシン上に tomcat が動作している場合は、Xcode のConsole に結果が表示される。 Webサーバに正しくアクセスできた場合は status code として 200 が返される。



    Console
    Content-Type: text/html;charset=UTF-8
    statusCode: 200
    
    
    
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <title>Apache Tomcat/9.0.94</title>
    ...(略)...
    
  23. この段階の Project を zip で圧縮したものは以下の通り。
  24. URLSession.zip


実機で動作させる


  1. 実機 (iphone)
  2. 開発環境 (mac)
  3. Webサーバ
  4. iPhone を開発用 Mac と同じネットワークに Wifi 接続する。
  5. 同一ネットワークでなくても構わないが、問題の切り分けを簡単にするために、同一の Wifi 親機に接続することを強く勧める。

  6. Webサーバが動作しているマシンの IP Address を確認する。 今回の ViewController.swift では、 WebサーバのIP Address が直にコーディングされていることに注意(説明を簡潔にするため)。
  7. thunderbolt ケーブルで、iPhone を Mac に接続する。
  8. Xcode を起動し、上のメニューから Windows → Devices and Simulators を選択する。

  9. Devices and Simulator のウィンドウが表示される。左側のウィンドウで Devices を選択すると、認識している iOS デバイスが表示される。
  10. iOS デバイスを最初に接続した時は、かなり大量のデータを Mac に吸い上げるため、認識されるまでに時間がかかる。 {2度目以降は、すぐに認識されて 'Connected' を表示され、実行デバイスとして選択できるようになる。


  11. ViewController.swift を編集し、アクセスするWebサーバの URL を変更する。
  12. この例ではWebサーバのIP アドレスが 192.168.11.11 である場合である。 IPアドレスを自分の環境に合わせて変更すること。

    "http://localhost:8080""http://192.168.11.11:8080/proj/NetData?data=1"
    ViewController.swift の変更点。IP Address 192.168.11.11 は各自の環境に合わせること。
    *** ViewController.swift	Mon Sep 23 11:46:04 2024
    --- ViewController2.swift	Mon Sep 23 14:42:23 2024
    ***************
    *** 10,16 ****
      class ViewController: UIViewController {
      
          @IBAction func tapButton(_ sender: Any) {
    !         let url = URL(string: "http://localhost:8080")!
               let request = URLRequest(url: url)
               let session = URLSession.shared
               session.dataTask(with: request) { (data, response, error) in
    --- 10,16 ----
      class ViewController: UIViewController {
      
          @IBAction func tapButton(_ sender: Any) {
    !         let url = URL(string: "http://192.168.11.11:8080/proj/NetData?data=1")!
               let request = URLRequest(url: url)
               let session = URLSession.shared
               session.dataTask(with: request) { (data, response, error) in
    
  13. iOS アプリの ATS (App Transport Security) を解除する。
  14. iOS 9 (2016) 以降は、iOS のアプリの Web アクセスは https を使うことが推奨され、基本的に http アクセスはできなくなった。 今回は開発用でもあり、簡単のため、危険性を理解した上で ATS を無効化し、 http アクセスを使うことにする。 具体的には Info.plist に次のエントリを追加する。

    App Transport Security Settings > Allow Arbitrary Loads キーを追加して、値を YES に設定する。

    1. Project Navigator で Info.plist を選択する。

    2. Key の一覧にある Information Property List をクリックし、 表示される「+」をさらにクリックして、 入力欄に App Transport Security Settings と入力する。 入力途中で候補が示されるので選択すればよい。

    3. App Transport Security Seeings キーが追加されるので、「+」を選択して、下位の項目のエントリ Allow Arbitrary Loads を作成する。

    4. App Transport Security Seeings > Allow Arbitrary Loads キーの値を YES に変更する。

  15. アプリの実行ターゲットを iOS デバイスの実機に変更する。ここでは iPhone14 とした。


  16. Xcode で iPhone が認識されているのに、アプリの実行デバイスとして選択できない場合は、 アプリがターゲットとしているiOS のバージョンが異なっている可能性が高い。ターゲットを実機に揃えること
    (例) アプリの設定で、General → Minimum Deployments → iOS + → debug: 17.0 and release 17.0

  17. 上部から実行ボタン をクリックする。

  18. 実デバイスで実行するときは、最初の1回はセキュリティエラーで失敗するので、iOSデバイス (たとえば iPhone) 上で認証の設定を行う。
  19. iPhone の設定 → 一般 → VPN とデバイス管理 → Apple Development appleアカウント → 信頼する
  20. また、実デバイスを指定して実行するには、その実デバイス(iPhone) が「開発者モード」に設定しておく必要がある。
  21. iphone: 設定 → Security and Privacy → Developer mode: on
  22. 上部から実行ボタン をクリックして、実デバイス上でアプリを実行する。 iPhone上の "Button" をクリックするたびに "1" というデータを Webアプリ (/proj/NetData) に送る。
  23. iPhone上での実行の様子
      
    Xcode のConsole表示

  24. 開発環境の Mac 上のブラウザでアクセスするとデータ(この例では "1.0" が3個)が送られたことがわかる。

  25. プロジェクトを zip でまとめたファイルは以下の通り
  26. URLSession2.zip


実機で動作させる (2)


ボタンを6個に増やしたプロジェクトは以下の通り。

URLSession3 の ViewController.swift
//
//  ViewController.swift
//  URLSession
//
//  Created by Yoshihisa Nitta on 2024/09/23.
//

import UIKit

class ViewController: UIViewController {

    @IBAction func tapUp(_ sender: Any) {
        wget(1)
    }
    
    @IBAction func tapLeft(_ sender: Any) {
        wget(2)
    }
    
    @IBAction func tapDown(_ sender: Any) {
        wget(3)
    }
    
    @IBAction func tapRight(_ sender: Any) {
        wget(4)
    }
    
    @IBAction func tapFire(_ sender: Any) {
        wget(5)
    }
    
    @IBAction func tapJump(_ sender: Any) {
        wget(6)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    func wget(_ v: Int) -> Bool {
        var url = URL(string: "http://172.17.136.190:8080/proj/NetData?data=\(v)")!
        let request = URLRequest(url: url)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if error == nil, let data = data, let response = response as? HTTPURLResponse {
                print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                print("statusCode: \(response.statusCode)")
                let s = String(data: data, encoding: String.Encoding.utf8) ?? ""
                print(s)
            }
        }.resume()
        return true
    }


}

URLSession3.zip