サーバーサイド初心者がiOSアプリ(SwiftUI)×サーバーサイド(PHP)やってみた


1.はじめに

きっかけ

Swift/SwiftUIでiOSアプリをリリースし始めて半年以上。
ゲーム系、ツール系と複数作ってきて、そろそろサーバーと通信できるようにしないとなと思い、試してみることにしました。

なぜPHP

とりあえず、"サーバーサイド フレームワーク"とか"サーバーサイド 言語"とかでググってみたところ、Pythonに色々とフレームワークがあることがわかり、最近流行だし機械学習とは関係ないけどPythonやったことあるって言ったら有利かなーとか思って、まずPythonで調べ始めました... が、 わ か ら な い...
諦めて、今度はPHPでも出来ることがわかったのでPHPに決めました。
(HTML, CSS, JavaScriptは触ったことがあり、馴染みがありそうだったので)

事前知識

そもそもサーバーサイド ド素人の私が事前知識として持っていたのは下記くらい。
・クライアント⇄AP(API)サーバー⇄DBサーバー
・ブラウザはHTTPリクエストをサーバーに送って、返ってきたレスポンスをもとに表示している
・アプリも同じように、HTTPリクエストを送ってAPIが返してきたデータを処理をするらしい

...WEBとiOSアプリでの違いってなに。。。

この状態から、色々と調べて、よし! できそうだぞ! となるまでに必要だった過程を記載します。

2.MAMPをインストールしてローカルにサーバーを立てる

・Apache
・MySQL
・PHP
をまとめてダウンロードしてくれて、ローカルでサーバーが立てられるというものです。

こちらの記事にお世話になりました。

(インストール方法の詳細は他のブログ等も参照しました)

とりあえずレンタルサーバー借りるか〜〜〜!? でもどれがいいかわから〜〜〜ん! となっていたのが解決しました...
普段シミュレーターではなく実機でテストしているので、同一ネットワーク内からアクセスする方法が記載されていたのも助かりました。

3.とりあえずなにか表示してみる

Document rootにあるindex.phpを編集していきます。(バックアップは取ったよ)

index.php
<!DOCTYPE html>
  <head>
    <meta charset="UTF-8">
    <title>MAMP</title>
  </head>
  <body>
    <?php
      print "hoge"
      //printの代わりにechoでも可。違いはググったら出てくる
      //ちなみにSwiftはセミコロンいらないけど、PHPは一番最後の文以外いるから注意
    ?>
  </body>
</html>

はい、表示されました。次ー!

index.php
<!DOCTYPE html>
  <head>
    <meta charset="UTF-8">
    <title>MAMP</title>
  </head>
  <body>
    <?php
        $arg1 = $_GET["arg1"];
        $arg2 = $_GET["arg2"];
        print "arg1=$arg1<br>arg2=$arg2";
    ?>
  </body>
</html>

パラメータも渡せました。

4.アプリからリクエストを送ってみる

いつもお世話になっているカピ通信さんのこちらの記事からコピペして試しました。
構造体の定義等は行わず、シンプルにDataからStringに変換して表示するコードにしました。

ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var result = ""

    /// データ読み込み処理
    func loadData() {

        /// URLの生成
        guard let url = URL(string: "http://192.168.3.18:8888?arg1=hoge&arg2=fuga") else {
            /// 文字列が有効なURLでない場合の処理
            return
        }

        /// URLリクエストの生成
        let request = URLRequest(url: url)

        /// URLにアクセス
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                guard let stringdata = String(data: data, encoding: .utf8) else {
                    print("Json decode エラー")
                    return
                }
                DispatchQueue.main.async {
                    result = stringdata
                }
            } else {
                print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
            }

        }.resume()      // タスク開始処理(必須)
    }

    var body: some View {
        ZStack {
            Text(result)
        }
        .onAppear() {
            loadData()
        }
    }
}

わお!

ここで私はやっと気づきました。ブラウザもアプリもやってることは変わらないのだと。
ただ返ってきたデータを、ブラウザの場合はユーザーが何もせずとも解釈してきれいに表示してくれているだけだと。
その解釈部分をSwiftで書けばいいのだと。
な〜んだ〜

というわけで、必要なものだけわたすぞ!

index.php
<?php
   $arg1 = $_GET["arg1"];
   $arg2 = $_GET["arg2"];
   print "arg1=$arg1, arg2=$arg2"; //<br>からしれっと, に変更してます
?>

でけた。

5.GETとPOST

ここで疑問が2つ。
1)ブラウザからURLにアクセスしたら画面に表示されるじゃん
2)IDとかパスワードとかどうやって送るの

GETメソッドだとリクエストパラメータで情報を渡すが、POSTメソッドだとボディ部に記載するとのこと。
そして、アドレスバーで検索するとGETメソッドになるらしい。(なのでPOSTしか受け付けなくするとWeb検索では見れないらしい)

ということで、POSTに書き換えてみる。

index.php
<?php
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        $arg1 = $_POST["arg1"];
        $arg2 = $_POST["arg2"];
        print "arg1=$arg1, arg2=$arg2";
    }
?>
ContentView.swift
//変更箇所のみ記載

        /// URLの生成
        guard let url = URL(string: "http://192.168.3.18:8888") else {
            /// 文字列が有効なURLでない場合の処理
            return
        }

        /// URLリクエストの生成
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = "arg1=hoge&arg2=fuga".data(using: .utf8)

結果
1)表示されていない

2)ボディ部から送れた
※本当にパスワード等を扱う場合は、ハッシュ化などが必要になってくるかと思うので、セキュリティまわりも追って勉強予定です。

6.今後の勉強方針

・セキュリティまわり
・DB作成、DBとの接続

続編、乞うご期待。