Help us understand the problem. What is going on with this article?

【Swift x Ruby】iOS端末とRuby on RailsサーバでHTTP通信

More than 3 years have passed since last update.

前回(【Swift x PHP】iOS端末とPHPサーバでHTTP通信)のRuby対応版になります。
サーバ側の処理言語としても人気なRuby on Railsに対応させていきましょう!
なんだか今日はハッピーです!Let's try!!

対象

Ruby on Railsの動作環境構築とMVC構成を理解していると良いでしょう。
また、iOS開発に関しても経験があるといいですが、今回作成するアプリをGitHubに上げているので未経験者でも始められると思います。

手順

  1. お好みのサーバにRuby on Rails環境を構築
  2. Install xcode
  3. Clone project file from GitHub
  4. Execute

1. Rails server

タイトルにRubyとありますが、フレームワークであるRuby on Railsを使っていきます。
Railsの雛形を作ったら、Controllerにparamsを使って、URLに含まれるパラメータを受け取る処理を記述します。出力にはrenderを使います。

render
指定したRHTMLを返す
:text 任意のテキストを指定して表示

Railsドキュメント

params
URLから送られてきた値やフォームで入力した値をparams[:パラメータ名]で取得する

Railsドキュメント

app/controllers/main_controller.rb
class MainController < ApplicationController
  def index
    render :text => "#{params[:title]} : #{params[:note]}"
  end
end

次に、上記のControllerが呼び出されるようにルーティングの設定を行います。
Rubyは小文字のファイル名、大文字使えるクラス名といった感じのお約束があります。それに従ってController名#メソッド名という書式でrootに設定しましょう。

config/routes.rb
Rails.application.routes.draw do
  root 'main_controller#index'
end

ここまで出来たら、Rails serverを起動させて以下のようにアクセスしてみましょう。titleパラメータに渡した文字列が表示されたら成功です。
http://192.168.22.2:3000/?title=ありがとう!&note=これからもよろしくね!
※IPアドレスは臨機応変に変更してください。

2. Install Xcode

Swift3とSwift2のコードを準備しているので準備するXcodeもお好きな方をご準備ください。
Androidほど開発環境構築に時間がかかることはないと思います。

3. iOS App Development

※Serverへの接続先が192.168.2.22であるものとして記述しているので、臨機応変に変えてください(GitHubのコードも同様です)

まず、iOS9以降でセキュリティ的に問題のあるHTTP通信が禁止されているので例外で許可させておきましょう。HTTPSで通信できるようにサーバを構築した場合はこの作業は必要ありません。

Info.plist
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>192.168.2.22</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <false/>
        </dict>
    </dict>
</dict>

次に、アプリの処理を実際に書いていきます。
clickButtonメソッド内に通信処理を書いています。
ユーザにTextFieldへ送信内容を入力してもらい、その内容を含めたURLでアクセスし、結果を取得・表示するといった流れを記述しています。
UIはお好みで!@IBOutletとなっている部分がStoryboardとリンクさせてる部分です。

Swift2 version

ViewController.swift
import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var resultLabel: UILabel!
    @IBOutlet weak var inputText1: UITextField!
    @IBOutlet weak var inputText2: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        inputText1.delegate = self
        inputText2.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func clickButton(sender: AnyObject) {
        if inputText1.text != "" && inputText2.text != "" {
            let title = inputText1.text!
            let note  = inputText2.text!

            // 接続先のURLにパラメータを追加
            let stringUrl = "http://192.168.2.22:3000/?title=\(title)&note=\(note)"
            // 文字列のURLからNSURLに変換
            let URL = NSURL(string: stringUrl.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)!
            // NSURLを引数にRequestの生成
            let req = NSURLRequest(URL: URL)

            // ここからが実際に通信をする所(非同期通信)
            let task = NSURLSession.sharedSession().dataTaskWithRequest(req, completionHandler: {
                (data, res, err) in
                // サーバから出力はありますか?
                if data != nil {
                    // あるみたいだから文字列に変換しておく
                    let text = NSString(data: data!, encoding: NSUTF8StringEncoding)
                    // 非同期通信内でUIに変更を加えるときのおまじないと思って!
                    dispatch_async(dispatch_get_main_queue(), {
                        self.resultLabel.text = text as String?
                    })
                }else{
                    // サーバから返事がないみたいだからエラー表示
                    dispatch_async(dispatch_get_main_queue(), {
                        self.resultLabel.text = "ERROR"
                    })
                }
            })
            task.resume()
        }
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool{
        //Close keyboard.
        textField.resignFirstResponder()

        return true
    }
}

Swift3 version
Swift3に対応するとともにアラートも追加してみました。
コードの解説はSwift2と変わらないところは省略しています。

ViewController.swift
import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var resultLabel: UILabel!
    @IBOutlet weak var inputText1: UITextField!
    @IBOutlet weak var inputText2: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        inputText1.delegate = self
        inputText2.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func clickButton(_ sender: AnyObject) {
        if inputText1.text != "" && inputText2.text != "" {
            let title = inputText1.text!
            let note  = inputText2.text!

            let stringUrl = "http://192.168.2.22:3000/?title=\(title)&note=\(note)"
            // Swift3からはNSがなくなってURLになりました
            let url = URL(string: stringUrl.addingPercentEscapes(using: String.Encoding.utf8)!)!
            // これもNSがなくなりました
            let req = URLRequest(url: url)

            // ここもNSがなくなりました
            let task = URLSession.shared.dataTask(with: req, completionHandler: {
                (data, res, err) in
                if data != nil {
                    let text = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
                    DispatchQueue.main.async(execute: {
                        self.resultLabel.text = text as String?
                    })
                }else{
                    DispatchQueue.main.async(execute: {
                        self.resultLabel.text = "ERROR"
                    })
                }
            })
            task.resume()
        }else{
            // 未入力なのにサーバにアクセスしようとしたら怒るようにした
            alert("error", messageString: "It is not entered.", buttonString: "OK")
        }
    }

    // 標準のアラートを表示させる
    func alert(_ titleString: String, messageString: String, buttonString: String){
        //Create UIAlertController
        let alert: UIAlertController = UIAlertController(title: titleString, message: messageString, preferredStyle: .alert)
        //Create action
        let action = UIAlertAction(title: buttonString, style: .default) { action in
            NSLog("\(titleString):Push button!")
        }
        //Add action
        alert.addAction(action)
        //Start
        present(alert, animated: true, completion: nil)
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{
        //Close keyboard.
        textField.resignFirstResponder()

        return true
    }
}

4. Execute

上部に送信した内容がフォーマットされて返ってきているのがわかると思います。
サンプルはPHPバージョンにも対応しています。
【Swift x PHP】iOS端末とPHPサーバでHTTP通信(Qiita)

結果

最後に

Rubyっていいですよね
プログラミング言語としても、宝石としても

サーバ構築とアプリ開発を別の人が担当して共同開発するのもいいですね。きっと面白くなります!!

以下がiOS側のサンプルです。
GitHub | AkkeyLab/SendMessage

planningdev
九州工業大学 ITサービス開発・運用団体
https://www.planningdev.com/
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした