【Swift x PHP】使用Swift和PHP在iOS设备与服务器之间进行HTTP通信

总而言之

如果要实现与服务器的通信,通常会使用库,但是这次我们将尝试不使用库进行实现。这对于学习Swift等方面可能会有帮助。实际上,可能还需要处理一些问题,比如超时处理和离线时的处理。

目标

我們假設能在服務器上建立PHP環境。同時,對於iOS開發有經驗會很好,但由於我們將這個應用程式上傳到GitHub,所以即使是沒有經驗的人也可以開始使用。

步驟

    在您喜欢的服务器上搭建PHP环境
    安装Xcode
    从GitHub克隆项目文件
    执行操作

1. PHP 服务器

使用Qiita上提供的方法在Mac上搭建本地服务器。(我使用了树莓派)

以下是PHP代码:
我已经准备了可以通过$_GET[]来接收的参数,其中包括title和note。然后使用print来输出文本。

<?php 
  $title = $_GET["title"];
  $note = $_GET["note" ];
  print "$title$note";
?>

不妨試試,輸入http://[IP地址]/RaspberryOne.php?title=給阿姐&note=請你用瀏覽器訪問,並寫下「我愛你」給阿姐。如果你被告白為「我愛你」,那就代表成功了。

2. 安装Xcode

请准备适用于我准备的Swift3和Swift2代码的Xcode版本,您可以选择自己喜欢的版本。我认为与Android相比,开发环境配置不会花费太多时间。

iOS应用程序开发

由于下面描述的连接服务器的地址为192.168.2.22,请根据实际情况作出灵活调整(GitHub的代码也同样适用此原则)。

首先,在iOS 9之后,禁止使用存在安全问题的HTTP通信,所以我们需要在例外情况下进行许可。如果已经建立了一个支持HTTPS通信的服务器,那么就不需要进行这个步骤了。

<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的版本

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/RaspberryOne.php?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版本,同时也添加了警告。
对于代码的解释,省略了与Swift2相同的部分。

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    //PHP
    @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.1.21/RaspberryOne.php?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
    }
}

执行

我想你会发现上方所发送的内容已经格式化返回来了。
如果在PHP端添加更多处理,这将成为一个可以收到阿小姐回复的应用!

結果

最后

明天是情人节(撰写这篇文章的时候)!来试着从iOS设备向PHP服务器表白吧?

让不同的人负责服务器架设和应用开发并共同开发也是一个不错的选择。这样肯定会变得很有趣!!

以下是iOS端的示例。
GitHub | AkkeyLab/SendMessage

bannerAds