AndroidでPHPにjsonを送受信する

#Androidでjsonを送受信する
この記事は調べながら作ったサンプルを自分用にまとめたものです。

AndroidでPHPにjsonを送受信するアプリを作ります。
例として、Androidで入力した文字列二つをPHPに送り、PHPで受け取った文字列を連結した後Androidに送り返します。
完成したアプリは以下のようになります。

<img width="400" alt="Screenshot_1574675979.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313474/1182545a-9079-e552-fa1f-6b5c16aab796.png">

#Androidのコード

layoutのidは

+ 二つのEditTextはeditText1とeditText2
+ ボタンはsubmit
+ 結果の表示TextはtextResult

としたときのMainActivityは以下のようになります。

```MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        submit.setOnClickListener {
            HitAPITask().execute("http://10.0.2.2/test/apistring.php")
        }
    }

    inner class HitAPITask : AsyncTask<String, String, String>() {

        override fun doInBackground(vararg params: String?): String? {
            var connection: HttpURLConnection? = null
            var reader: BufferedReader? = null
            var buffer: StringBuffer

            try {
                val url = URL(params[0])
                connection = url.openConnection() as HttpURLConnection

                //送信するための設定
                connection.requestMethod = "POST"
                connection.setInstanceFollowRedirects(false)

                connection.setDoOutput(true)
                connection.setDoInput(true)

                //送信する文字列の取得
                val text1 = findViewById<EditText>(R.id.editText1).text.toString()
                val text2 = findViewById<EditText>(R.id.editText2).text.toString()

                //送信するjsonの作成
                val json = "{\"text1\":\"" + text1 + "\",\"text2\":\"" + text2 + "\"}"

                //再び送信するための設定
                connection.setRequestProperty("Accept-Language", "jp")
                connection.setRequestProperty("Content-Type", "application/json; charset=utf-8")

                //ostreamへjsonを書き込む
                val os = connection.getOutputStream()
                val ps = PrintStream(os)
                ps.print(json)
                ps.close()

                //Apiから返ってきたjsonの処理
                val stream = connection.getInputStream()
                reader = BufferedReader(InputStreamReader(stream, "UTF-8"))
                buffer = StringBuffer()

                var line: String?
                while (true) {
                    line = reader.readLine()
                    if (line == null) {
                        break
                    }
                    buffer.append(line)
                    Log.d("CHECK", buffer.toString())
                }

                //jsonから結果を取り出す
                val jsonText = buffer.toString()
                val jsonObject = JSONObject(jsonText)
                val result = jsonObject.getString("result")

                return result

                //例外が起こった時の処理
            } catch (e: MalformedURLException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            } catch (e: JSONException) {
                e.printStackTrace()
            } finally {
                connection?.disconnect()
                try {
                    reader?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }

            //例外が起こった時の返り値
            return null
        }


        override fun onPostExecute(rtn: String?) {
            super.onPostExecute(rtn)
            if (rtn == null) rtn

            textResult.text = rtn

        }
    }
}
```

ポイント

* HTTP通信にはAsyncTaskで非同期通信する。
* jsonを送信するにはsetRequestPropertyを使う。phpで$_GETを使って受け取るにはapplication/jsonの部分を変える必要があるはず。最初はこれをやりたかったがうまくいかなかった。

```
connection.setRequestProperty("Accept-Language", "jp")
connection.setRequestProperty("Content-Type", "application/json; charset=utf-8")
```

+ 送信にはgetOutputStreamでostreamにjsonを書き込む

```
val os = connection.getOutputStream()
val ps = PrintStream(os)
ps.print(json)
ps.close()
```

+ 通信するためにはpermissionで許可をしなければならない。

```AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
```
+エミュレータでApacheのサーバのPHPと通信する。その場合URLはlocalhostではなくhttp://10.0.2.2となる。
さらに、10.0.2.2との通信に許可が必要なので、newtwork_security_config.xmlを用意する。
AndroidManifest.xmlにSecurityConfigでnewtwork_security_config.xmlを使うことを教えておく。

```AndroidManifest.xml
<application android:networkSecurityConfig="@xml/network_security_config"/>
```

```newtwork_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="false">10.0.2.2</domain>
    </domain-config>
</network-security-config>
```

#PHPのコード

```apistring.php
<?php
    $json = file_get_contents('php://input');

    $array = json_decode($json);
 
    $a = $array->text1;

    $b = $array->text2;

    $sum = $a . $b;
    //$sumsum = 3;

    $ary = array('result'=>$sum);

    echo json_encode($ary);
?>
```

ポイント

+ POSTではなくfile_get_contents('php://input')でjsonを受け取る。

#最後に
理解せずに書いている部分も多いので少しずつ勉強していこう。

#追記
KotlinにはString Templateというものがあるらしく、変数を文字列に埋め込むのは$記号で簡単にできるらしい。たとえば、

```
val json = "{\"text1\":\"" + text1 + "\",\"text2\":\"" + text2 + "\"}"
```

これは

```
val json = "{\"text1\":\"$text1\",\"text2\":\"$text2\"}"
```

とできる。

参考
[JavaプログラマがKotlinで便利だと感じること](https://qiita.com/koher/items/cb91dbbff9b14575f498)

#参考文献
[Android Httpでデータ取得](https://qiita.com/yamikoo@github/items/2a40f93509f4154ccd48)
[AndroidでのHTTP通信](https://qiita.com/a_nishimura/items/19cf3f60ad1dd3f66a84)
[AndroidからAPIを叩いてJSON取って中身を表示させるまで](https://qiita.com/minme31/items/a9636cb0453524c64e67)
[JSON形式でPOSTされたデータの受信方法](http://www.initialsite.com/g03/14794)
[【PHP】JSONデータのPOST受け取りで application/x-www-form-urlencoded とapplication/json の両方に対応](https://qiita.com/Kunikata/items/2b410f3cc535e4104906)