반응형



안드로이드 앱이  PHP 프로그램을 매개로 하여 MySQL 데이터베이스 서버에 데이터를 저장하는 간단한 예제입니다. 



1. Apache2, MySQL, PHP7 설치

2. 데이터베이스 및 테이블 생성

3. 웹브라우저로 PHP 동작  테스트

4. Android 앱에서 테스트

5. 코드 설명

6. 관련 포스팅

7. 참고


2015. 11. 21 최초 작성 

2019. 11. 17 androidx 사용하도록 변경

2020.  7. 14  MySQL을 디폴트로 바꾸는 방법 추가 



안드로이드 앱에서 바로 MySQL에 접속한다면 구현이 간단할 수 있습니다.

하지만 리버스 엔지니어링을 통해 안드로이드 앱에서 소스코드를 추출하게 되면 서버 아이피와 MySQL 서버 접속용 아이디와 패스워드가 유출될 수 있습니다. 


그래서 웹서버에서 실행되는 PHP를 이용하여 진행하게 됩니다.  안드로이드 앱의 코드를 추출한다 해도 서버 IP와 실행되는 PHP 파일 이름만 알 수 있습니다. 

하지만 해당 IP와 PHP 파일에 대한 정보를 통해 악용할 수도 있기 때문에 추가로 필요한 작업이 있을 수도 있을 듯하지만 제가 아는 범위에서 벗어나서 논외로 합니다. 

 



1. Apache2, MySQL, PHP7 설치

서버로 사용하려는 운영체제에 따라 1-1 또는 1-2를 진행하세요.

1-1. WIndows

다음 포스팅을 참고하여 윈도우에 WAMP( Apache2, MySQL , PHP7)를 설치합니다. 



윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

http://webnautes.tistory.com/1206 




오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 PHP > Version을 선택합니다. 


사용가능한 PHP 버전이 보이는 데 최신 버전인 7.2.18를 선택합니다. 글 작성시점과 버전이 다를 수 있습니다. 





1-2. Ubuntu

다음 포스팅을 참고하여 Ubuntu에  LAMP( Apache2, MySQL , PHP7)를 설치합니다. 



Ubuntu 18.04에 LAMP ( Apache2, MySQL , PHP7) 설치하는 방법

http://webnautes.tistory.com/1185    





2. 데이터베이스 및 테이블 생성 


2-1. MySQL에서 데이터베이스를 새로 생성하고  해당 데이베이스를 접근할 수 있는 사용자를 추가하는 방법을 설명합니다. 


서버 컴퓨터의 운영체제가 Windows라면 2-2, Ubuntu라면 2-3을 진행하세요.




2-2. 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다. 


로그인 사용자로 root가 지정되어 있습니다. OK 버튼을 클릭합니다. 




Enter password: 라는 메시지가 보입니다.  설치시 설정해주었던 root 암호를 입력해주면 로그인이 완료됩니다. 


root 암호를 설정한 적이 없다면 엔터를 입력하여 진행할 수도 있지만 포스팅의 1-1을 다시 진행하여 root 암호를 부여해주세요.. 



이제 2-4를 진행하세요.




2-3. Ubuntu 18.04에서 설치한 MySQL에서는 디폴트로 auth_socket 플러그인을 사용하기 때문에 기존에 사용하던 방법(root 계정의 암호입력)으로 로그인이 되지 않습니다. 


확인을 못해봤는데 Ubuntu 16.04에서 최신 버전 MySQL을 사용한다면 같은 상황이 있을 수 있습니다. 


webnautes@webnautes-pc:~$ mysql -u root -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'



sudo 명령시 입력하는 사용자 암호 입력으로 기존 로그인을 대체합니다.


webnautes@webnautes-pc:~$ sudo mysql
[sudo] webnautes의 암호:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.7.22-0ubuntu18.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql>




2-4. 윈도우와 우분투에서 동일하게 진행하는 부분입니다.


데이터베이스를 생성합니다. 


mysql> create database 데이터베이스이름 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


mysql> create database testdb default character set utf8;

Query OK, 1 row affected (0.00 sec)



새로 생성한 데이터베이스를 사용할 사용자를 생성합니다. 


mysql> create user 사용자이름 identified by '패스워드';


mysql> create user webnautes identified by 'apple9!';

Query OK, 0 rows affected (0.01 sec)



앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.  


mysql> GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';


mysql> grant all privileges on testdb.* to 'webnautes'@'localhost' identified by 'apple9!';

Query OK, 0 rows affected, 1 warning (0.00 sec)



quit를 입력하여 MySQL 콘솔을 종료합니다.




2-5.  MySQL 콘솔에 새로 생성한 사용자로 접속합니다. 


우분투에서는 다음처럼 MySQL 로그인을 합니다. 사용자 이름은 새로 생성한 데이터베이스 접근권한을 가진 사용자 입니다. 

Enter password: 에 사용자의 암호를 입력해줍니다. 


$ mysql -u 사용자이름 -p

Enter password:



윈도우에서는 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다.


새로 생성한 데이터베이스 접근권한을 가진 사용자 이름을 적고 OK 버튼을 클릭합니다. 




Enter password: 메시지가 보이면 사용자의 암호를 입력해줍니다. 


Enter password:




2-6. 데이터베이스 testdb에 필요한 테이블 person을 생성하고  MySQL이 잘 동작하는지 여부를 다음처럼 확인합니다. 


앞에서 생성해두었던 데이터베이스 testdb가 보입니다.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| testdb             |
+--------------------+
2 rows in set (0.00 sec)


데이터베이스 testdb를 사용하도록 하고

mysql> use testdb;
Database changed



다음 명령을 복사 후 붙여넣기 해서 person 테이블을 생성합니다.

create table person(
      id bigint(20) unsigned not null auto_increment,
      name varchar(255) not null,
      country varchar(255) not null,
      primary key (id)
)  DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


mysql> create table person(
    ->      id bigint(20) unsigned not null auto_increment,
    ->      name varchar(255) not null,
    ->      country varchar(255) not null,
    ->      primary key (id)
    -> )  DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
Query OK, 0 rows affected (0.03 sec)


person 테이블이 생성되었습니다.


mysql> show tables;
+--------------+
| Tables_in_db |
+--------------+
| person       |
+--------------+
1 row in set (0.00 sec)


데이터 하나를 테이블에 입력 해봅니다. 


mysql> insert into person(name, country) values('test', 'test');
Query OK, 1 row affected (0.00 sec)


쿼리를 해서 데이터를 다시 가져와 봅니다.

 
mysql> select * from person;
+----+------+---------+
| id | name | country |
+----+------+---------+
|  1 | test | test    |
+----+------+---------+
1 row in set (0.00 sec)


person 테이블의 데이터를 초기화합니다. 


mysql> truncate person;
Query OK, 0 rows affected (0.01 sec)


테이블이 초기화 되었습니다.


mysql> select * from person;

Empty set (0.00 sec)


MySQL 콘솔을 종료합니다.


mysql> exit
Bye




3. 웹브라우저로 PHP 동작  테스트

Android 앱으로 테스트를  진행하기 전에 다음 PHP 코드를  웹 브라우저로 간단한 테스트를 해보겠습니다.


다음 두 개의 파일이 필요합니다.

dbcon.php

MySQL 서버 접속을 위해 사용되는 코드입니다. 


insert.php

지정해 높은 데이터베이스의 테이블에 데이터를 저장하기 위해 사용됩니다.



dbcon.php


<?php

    $host = 'localhost';
    $username = 'webnautes'; # MySQL 계정 아이디
    $password = 'apple9!'; # MySQL 계정 패스워드
    $dbname = 'testdb'# DATABASE 이름


    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
   
    try {

        $con = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8",$username, $password);
    } catch(PDOException $e) {

        die("Failed to connect to the database: " . $e->getMessage());
    }


    $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

    if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
        function undo_magic_quotes_gpc(&$array) {
            foreach($array as &$value) {
                if(is_array($value)) {
                    undo_magic_quotes_gpc($value);
                }
                else {
                    $value = stripslashes($value);
                }
            }
        }

        undo_magic_quotes_gpc($_POST);
        undo_magic_quotes_gpc($_GET);
        undo_magic_quotes_gpc($_COOKIE);
    }

    header('Content-Type: text/html; charset=utf-8');
    #session_start();
?>




insert.php


<?php

    error_reporting(E_ALL);
    ini_set('display_errors',1);

    include('dbcon.php');


    if( ($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit']))
    {

        $name=$_POST['name'];
        $country=$_POST['country'];

        if(empty($name)){
            $errMSG = "이름을 입력하세요.";
        }
        else if(empty($country)){
            $errMSG = "나라를 입력하세요.";
        }

        if(!isset($errMSG))
        {
            try{
                $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                $stmt->bindParam(':name', $name);
                $stmt->bindParam(':country', $country);

                if($stmt->execute())
                {
                    $successMSG = "새로운 사용자를 추가했습니다.";
                }
                else
                {
                    $errMSG = "사용자 추가 에러";
                }

            } catch(PDOException $e) {
                die("Database error: " . $e->getMessage());
            }
        }

    }
?>

<html>
  <body>
        <?php
        if (isset($errMSG)) echo $errMSG;
        if (isset($successMSG)) echo $successMSG;
        ?>
       
        <form action="<?php $_PHP_SELF ?>" method="POST">
            Name: <input type = "text" name = "name" />
            Country: <input type = "text" name = "country" />
            <input type = "submit" name = "submit" />
        </form>
 
  </body>
</html>




3-1. 윈도우라면 C:\wamp64\www\ 경로에 파일을 생성합니다.



3-2. 우분투라면 /var/www/html/ 경로에 파일을 생성합니다.



3-3. 웹브라우저에서  localhost/insert.php 주소로 접속하면 아래와 같은 화면이 보이게 됩니다. 





최근에 나온(2020. 7. 14 기준)  WampServer의 경우 프로그램 설치시 MySQL를 선택해야 설치되며  디폴트 데이터베이스가 아래 스크린샷처럼 MariaDB로 되어 있습니다. 

WampServer 트레이 아이콘에서 왼쪽 버튼으로 클릭하면 보입니다. 


MySQL을 디폴트로 변경하지 않으면 다음과 같은 에러가 날 수 있습니다. 

얼마전 이 에러를 질문하신분이 있었는데 이런 문제가 있는줄 몰랐네요..


Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'webnautes'@'localhost' (using password: YES) 





WampServer 트레이아이콘에서 마우스 오른쪽 버튼을 눌러  보이는 메뉴에서 Tools > Invert default DBMS MariaDB <-> MySQL을 선택합니다. 

디폴트 DBMS가 MariaDB에서 MySQL으로 변경되게 됩니다. 



다음처럼 MySQL이 디폴트로 바뀌어야 합니다. 





정상적으로 테이블에 데이터가 입력되면 출력되는 메시지입니다.




이름이나 나라를 입력하지 않으면 에러 메시지를 출력하도록 되어 있습니다.






3-4. 안드로이드 폰의 웹브라우저에서도 테스트해 봅니다.




접속에 문제가 있다면 다음 포스트 16번부터  참고하세요.



윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

 http://webnautes.tistory.com/1206 





3-5. MySQL에서 확인해보면 데이터가 정상적으로 입력된 것을 볼 수 있습니다. 


SELECT 문으로 testdb 데이터베이스에 있는 Person 테이블의 내용을 조회합니다.

웹에서 입력한 이름과 주소가 제대로 입력되었는지 확인가능합니다.





4. Android 앱에서 테스트


웹서버의 PHP 파일을 통해 데이터베이스에 데이터를 저장하는 안드로이드 앱을 작성합니다.



4-1. insert.php 파일을 다음 코드로 변경합니다. 


<?php

    error_reporting(E_ALL);
    ini_set('display_errors',1);

    include('dbcon.php');


    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


    if( (($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit'])) || $android )
    {

        // 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.

        $name=$_POST['name'];
        $country=$_POST['country'];

        if(empty($name)){
            $errMSG = "이름을 입력하세요.";
        }
        else if(empty($country)){
            $errMSG = "나라를 입력하세요.";
        }

        if(!isset($errMSG)) // 이름과 나라 모두 입력이 되었다면
        {
            try{
                // SQL문을 실행하여 데이터를 MySQL 서버의 person 테이블에 저장합니다.
                $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                $stmt->bindParam(':name', $name);
                $stmt->bindParam(':country', $country);

                if($stmt->execute())
                {
                    $successMSG = "새로운 사용자를 추가했습니다.";
                }
                else
                {
                    $errMSG = "사용자 추가 에러";
                }

            } catch(PDOException $e) {
                die("Database error: " . $e->getMessage());
            }
        }

    }

?>


<?php
    if (isset($errMSG)) echo $errMSG;
    if (isset($successMSG)) echo $successMSG;

$android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
 
    if( !$android )
    {
?>
    <html>
      <body>

            <form action="<?php $_PHP_SELF ?>" method="POST">
                Name: <input type = "text" name = "name" />
                Country: <input type = "text" name = "country" />
                <input type = "submit" name = "submit" />
            </form>
     
      </body>
    </html>

<?php
    }
?>




4-2. AndroidManifest.xml 매니페스트 파일의  manifest 태그 하위 항목으로 인터넷 접근 허용 퍼미션을 추가합니다.

android 9.0  이상에서 동작하게 하려면 usesCleartextTraffic 옵션도 추가해야 합니다. 해주지 않으면 “cleartext http traffic to not permitted” 라는 에러가 발생합니다.  



<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.webnautes.phptest">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:usesCleartextTraffic="true"
        android:allowBackup="true"


 


4-3. activity_main.xml 레이아웃 파일을 아래 내용으로 바꿉니다. 



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name"
        android:id="@+id/textView_main_name" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText_main_name" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Country"
        android:id="@+id/textView_main_country" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText_main_country" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Insert"
        android:id="@+id/button_main_insert" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:id="@+id/textView_main_result" />

</LinearLayout>




4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다.



다음 줄에 있는 IP 주소를 아파치 웹서버가 설치된  컴퓨터의 IP로 수정하세요.

private static String IP_ADDRESS = "IP주소";


안드로이드 에뮬레이터와 서버가 같은 컴퓨터에 동작하는 경우에는 다음 아이피를 입력합니다.

Android Studio의 에뮬레이터  - 10.0.2.2

GenyMotion - 192.168.56.1  


package com.tistory.webnautes.phptest;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedReader;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.net.HttpURLConnection;
import java.net.URL;


public class MainActivity extends AppCompatActivity {

    private static String IP_ADDRESS = "IP주소";
    private static String TAG = "phptest";

    private EditText mEditTextName;
    private EditText mEditTextCountry;
    private TextView mTextViewResult;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEditTextName = (EditText)findViewById(R.id.editText_main_name);
        mEditTextCountry = (EditText)findViewById(R.id.editText_main_country);
        mTextViewResult = (TextView)findViewById(R.id.textView_main_result);

        mTextViewResult.setMovementMethod(new ScrollingMovementMethod());


        Button buttonInsert = (Button)findViewById(R.id.button_main_insert);
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String name = mEditTextName.getText().toString();
                String country = mEditTextCountry.getText().toString();

                InsertData task = new InsertData();
                task.execute("http://" + IP_ADDRESS + "/insert.php", name,country);


                mEditTextName.setText("");
                mEditTextCountry.setText("");

            }
        });

    }



    class InsertData extends AsyncTask<String, Void, String>{
        ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = ProgressDialog.show(MainActivity.this,
                    "Please Wait", null, true, true);
        }


        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            progressDialog.dismiss();
            mTextViewResult.setText(result);
            Log.d(TAG, "POST response  - " + result);
        }


        @Override
        protected String doInBackground(String... params) {

            String name = (String)params[1];
            String country = (String)params[2];

            String serverURL = (String)params[0];
            String postParameters = "name=" + name + "&country=" + country;


            try {

                URL url = new URL(serverURL);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();


                httpURLConnection.setReadTimeout(5000);
                httpURLConnection.setConnectTimeout(5000);
                httpURLConnection.setRequestMethod("POST");
                httpURLConnection.connect();


                OutputStream outputStream = httpURLConnection.getOutputStream();
                outputStream.write(postParameters.getBytes("UTF-8"));
                outputStream.flush();
                outputStream.close();


                int responseStatusCode = httpURLConnection.getResponseCode();
                Log.d(TAG, "POST response code - " + responseStatusCode);

                InputStream inputStream;
                if(responseStatusCode == HttpURLConnection.HTTP_OK) {
                    inputStream = httpURLConnection.getInputStream();
                }
                else{
                    inputStream = httpURLConnection.getErrorStream();
                }


                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

                StringBuilder sb = new StringBuilder();
                String line = null;

                while((line = bufferedReader.readLine()) != null){
                    sb.append(line);
                }


                bufferedReader.close();


                return sb.toString();


            } catch (Exception e) {

                Log.d(TAG, "InsertData: Error ", e);

                return new String("Error: " + e.getMessage());
            }

        }
    }


}




4-5.  안드로이드 프로젝트를 빌드하여 앱을 테스트할 디바이스 또는 에뮬레이터에 설치합니다.

앱을 실행시키면 다음과 같은 화면이 보입니다.




테스트 문자열을 입력하고  INSERT를 터치합니다. 




성공한 경우 SQL문 처리 성공이라는 메시지가 보이게 됩니다.




Error: connect timed out 메시지가 보인다면 본 포스트의 3-4를 다시 확인해보세요.

방어벽 문제 일 수 있습니다. 




4-6. MySQL에서 확인해보면 정상적으로 입력된 것을 볼 수 있습니다.





5. 코드 설명

다음 두 단계를 거쳐서 안드로이드 앱의 데이터가 MySQL 서버에 저장됩니다. 


  1. 안드로이드 앱에서 POST 방식으로 PHP 코드에 데이터를 전달합니다. 

  2. PHP 코드에서 MySQL 서버에 접속하여 전달받은 데이터를 저장합니다.



우선 안드로이드 앱 코드를 살펴보겠습니다. 


@Override
protected String doInBackground(String... params) {

String name = (String)params[1];
String country = (String)params[2];


      // 1. PHP 파일을 실행시킬 수 있는 주소와 전송할 데이터를 준비합니다.

      // POST 방식으로 데이터 전달시에는 데이터가 주소에 직접 입력되지 않습니다.
String serverURL = (String)params[0];



      // HTTP 메시지 본문에 포함되어 전송되기 때문에 따로 데이터를 준비해야 합니다. 

      // 전송할 데이터는 “이름=값” 형식이며 여러 개를 보내야 할 경우에는 항목 사이에 &를 추가합니다.     

      // 여기에 적어준 이름을 나중에 PHP에서 사용하여 값을 얻게 됩니다.

      String postParameters = "name=" + name + "&country=" + country;


try {
            // 2. HttpURLConnection 클래스를 사용하여 POST 방식으로 데이터를 전송합니다.
URL url = new URL(serverURL); // 주소가 저장된 변수를 이곳에 입력합니다. 


            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

httpURLConnection.setReadTimeout(5000); //5초안에 응답이 오지 않으면 예외가 발생합니다.

httpURLConnection.setConnectTimeout(5000); //5초안에 연결이 안되면 예외가 발생합니다.

httpURLConnection.setRequestMethod("POST"); //요청 방식을 POST로 합니다.
httpURLConnection.connect();


OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(postParameters.getBytes("UTF-8")); //전송할 데이터가 저장된 변수를 이곳에 입력합니다. 인코딩을 고려해줘야 합니다.

outputStream.flush();
outputStream.close();


            // 3. 응답을 읽습니다.   

int responseStatusCode = httpURLConnection.getResponseCode();
Log.d(TAG, "POST response code - " + responseStatusCode);

InputStream inputStream;
if(responseStatusCode == HttpURLConnection.HTTP_OK) {

                  // 정상적인 응답 데이터
inputStream = httpURLConnection.getInputStream();
}
else{

                  // 에러 발생 

inputStream = httpURLConnection.getErrorStream();
}


            // 4. StringBuilder를 사용하여 수신되는 데이터를 저장합니다.
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

StringBuilder sb = new StringBuilder();
String line = null;

while((line = bufferedReader.readLine()) != null){
sb.append(line);
}


bufferedReader.close();

            

            // 5. 저장된 데이터를 스트링으로 변환하여 리턴합니다.
return sb.toString();


} catch (Exception e) {

Log.d(TAG, "InsertData: Error ", e);

return new String("Error: " + e.getMessage());
}

}




PHP 코드를 보겠습니다. 

 

        // 1. 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.
        $name=$_POST['name'];
        $country=$_POST['country'];


    
        // 2. 입력안된 항목이 있을 경우 에러 메시지를 생성합니다.
        if(empty($name)){
            $errMSG = "이름을 입력하세요.";
        }
        else if(empty($country)){
            $errMSG = "나라를 입력하세요.";
        }

        // 3. 에러 메시지가 정의안되어 있다면 이름과 나라 모두 입력된 경우입니다. 

        if(!isset($errMSG))
        {
            try{
               // 4. SQL문을 실행하여 데이터를 MySQL 서버의 person 테이블에 저장합니다.
                $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                $stmt->bindParam(':name', $name);
                $stmt->bindParam(':country', $country);

                // 5. SQL 실행 결과를 위한 메시지를 생성합니다.
                if($stmt->execute())
                {
                    $successMSG = "새로운 사용자를 추가했습니다.";
                }
                else
                {
                    $errMSG = "사용자 추가 에러";
                }



6. 관련 포스팅



Android PHP MySQL 예제 - 데이터베이스에서 데이터를 JSON 형식으로 가져오기

http://webnautes.tistory.com/829


Android PHP MySQL 예제 - 데이터베이스 질의(query) 결과 출력하기

https://webnautes.tistory.com/1159


Android PHP MySQL 예제  - 데이터베이스에 데이터 저장 및 JSON 형식으로 가져오는 예제 프로젝트

http://webnautes.tistory.com/1189  





7. 참고


[1]  http://www.simplifiedcoding.net/php-android-tutorial-part-1/ 


[2]  http://www.simplifiedcoding.net/android-login-and-registration-with-php-mysql/ 


[3]  http://www.tutorialspoint.com/android/android_php_mysql.htm 



반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. 이전 댓글 더보기
  2. 정유환 2020.06.12 17:09

    안녕하세요.
    데이터베이스에 데이터 입력이 잘 안돼서 질문 드립니다.
    웹에서 php파일을 이용해서 데이터를 입력하면 데이터베이스에 정상적으로 추가가 되는데
    안드로이드에서 데이터 입력을 하니 아무 변화가 없네요..

    protected String doInBackground(String... params) {
    String serverURL = (String)params[0];
    Log.d("URL: ", serverURL);
    String postParameters = "";
    for(int i=0; i<20; ++i) {
    postParameters += "t"+ (i+1) + "=" + t[i];
    if(i!=19)
    postParameters += '&';
    }

    Log.d("A : ",postParameters);

    이 결과로 postParameters 값은
    t1=1&t2=1&t3=1&t4=0&t5=1&t6=1&t7=1&t8=0&t9=1&t10=1&t11=0&t12=0&t13=0&t14=0&t15=0&t16=0&t17=0&t18=0&t19=0&t20=0
    이런 형태로 나옵니다. 코드 나머지 부분은 예제랑 같구요.
    post response code는 200으로 정상적으로 연결은 된 것 같습니다. 혹시 문제점을 알 수 있을까요?? 감사합니다...

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.12 18:41 신고

      서버쪽 로그에 php 접근이 어떻게 처리되었나 우선 살펴보세요

  3. ILLHYHL 2020.06.16 11:27

    kotlin 방식의 코드는 없는건가요? 올려주실수있나요??

  4. 익듀 2020.06.16 13:38

    Warning: include(dbcon.php): failed to open stream: No such file or directory in C:\wamp64\www\insert.php.php on line 6
    Warning: include(): Failed opening 'dbcon.php' for inclusion (include_path='.;C:\php\pear') in C:\wamp64\www\insert.php.php on line 6

    다양한 방법으로 시도 중 인데 혹시 알고있는 오류인가요 ?

  5. sunrise 2020.06.18 01:51

    mAdapter = new UsersAdapter(this, mArrayList);

    PersonalData personalData = new PersonalData();

    이 부분에서 Type parameter cannot be instantiated dilectly 라며 빨간줄이 생깁니다.
    어떻게 해결해야 할까요?

  6. dbmaker 2020.06.23 15:14

    Deprecated: Function get_magic_quotes_gpc() is deprecated in C:\Apache24\htdocs\dbcon.php on line 23
    라고 뜨는데 혹시
    코드를 어떻게 수정해야하는지 알려주실 수 있나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.23 20:16 신고

      해당 함수가 나중에 제거될수 있다는 메시지입니다. 에러는 아니고 지금 실행하는데에도 문제가 되지는 않지만 나중을 생각하면 해당 함수가 대체되는 함수를 찾아봐야 할듯합니다.

      찾아보니 다음처럼 대체하라고 하네요

      I suggest replacing foreach by "stripslashes_deep":

      Example #2 Using stripslashes() on an array on
      <http://www.php.net/manual/en/function.stripslashes.php>:

      <?php
      function stripslashes_deep($value)
      {
          $value = is_array($value) ?
                      array_map('stripslashes_deep', $value) :
                      stripslashes($value);

          return $value;
      }
      ?>

      This gives:

      <?php
      if((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())    || (ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off")) ){
          stripslashes_deep($_GET);
          stripslashes_deep($_POST);
          stripslashes_deep($_COOKIE);
      }
      ?>

      출처 링크입니다.

      https://www.php.net/manual/en/function.get-magic-quotes-gpc.php

  7. dsfew 2020.06.30 20:52

    Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'user'@'localhost' (using password: YES)
    해당 에러가 계속 발생하는데, 무엇이 문제일까요? 복사해서 붙여 넣었고, phpMyAdmin에서 확인해도 패스워드 지정 돼 있고 localhost로 host 지정이 다 돼 있는데도 이 문제가 계속 발생하네요....

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.30 20:55 신고

      포스트에서 아래부분을 다시 확인해보세요.

      앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.  

      mysql> GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.30 20:56 신고

      데이터베이스에 접근할 수 있는 권한이 제대로 부여안된 상태입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.14 22:44 신고

      늦었지만 답글을 답니다. 3-3을 확인해보세요.

  8. Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.14 18:24 신고

    안드로이드 logcat에서는 문제없이 보내진거 같은데,
    2020-07-14 18:14:14.067 27657-27685/net.**** D/php: POST response code - 200
    2020-07-14 18:14:14.090 27657-27657/net.***** D/php: POST response - fQD2bbb2RfyLr4VTB0yCvn:

    php에서 받질 못합니다ㅠㅠ db랑 연동 할 필요없고 그냥 웹에 띄우기만 하려하는데, 어디가 문제인걸까요?
    이름은 몇번이고 확인을 했습니다 ㅠㅠ
    <?php
    error_reporting(E_ALL);
    ini_set('display_errors',1);

    $token= !empty($_POST['token'])? $_POST['token']:'no';

    echo($token);
    ?>

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.14 18:27 신고

      포스트 코드 기준으로 다음 부분을 확인해보세요

      String postParameters = "name=" + name + "&country=" + country;

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.14 18:32 신고

      InsertData task1 = new InsertData();
      task1.execute("http://" + apacheip + "/token.php", token);

      라고 적어준뒤 그 부분에서는 이렇게 적었습니다!
      String token = (String)params[1];
      String serverURL = (String)params[0];
      String postParameters = "token=" + token;

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.15 10:10 신고

      혹시 php에서 더 적어줘야 할 게 있는건가요?? php파일에 딱 위와 같이 저렇게만 적었습니다 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.15 10:22 신고

      아직 테스트를 못해봤습니다. 급하시면 포스트 코드로 동작 확인한후 원하는 방식으로 수정해보세요

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.15 17:59 신고

      아 넵넵 감사합니다 ㅠㅠ 문제 찾는게 쉽지가 않네요 ....ㅎㅎ

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.16 01:59 신고

      https://stackoverflow.com/questions/36437075/send-data-from-android-to-server-localhost/36437203

      위와 같은 문제 인거 같습니다.
      하지만, 해결이 아직이네요ㅠㅠㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.16 06:36 신고

      다음코드를 테스트해보세요


      https://androidexample.com/How_To_Make_HTTP_POST_Request_To_Server_-_Android_Example/index.php?view=article_discription&aid=64&aaid=89

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.18 20:09 신고

      시도해보았습니다:) 안드로이드쪽에서는 보낸 후의 result 결과는 잘 뜨는데 역시나 php상 웹페이지에서 확인이 불가하네요 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.20 23:15 신고

      php가 계속 리플레쉬되다가 안드로이드에서 문자열을 받으면 보여줘야 할거 같은데.. 웹에 익숙하지 않아서.. 구현이 쉽지 않군요

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.22 14:12 신고

      꾸준한 답변 감사드립니다~~~
      POST한 값이 웹페이지에 보여지지 않는 문제를 새로운 파일에 보여줄 내용을 적어주고 그 파일의 내용 전체를 띄우는 방식으로 해결했습니다!!

      <?php
      error_reporting(E_ALL);
      ini_set('display_errors',1);
      $filename="000.txt";
      $msg=file_get_contents($filename);
      if($msg=""){
      $token= !empty($_POST['token'])? $_POST['token']:'No msg';
      if($token!='No msg'){
      file_put_contents($filename,$token,FILE_APPEND);
      }
      }
      $msg=file_get_contents($filename);
      echo $msg;
      ?>

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.22 15:52 신고

      해결되서 다행입니다

  9. jongha 2020.07.22 22:08

    포스팅 하시느라 고생많으셨습니다.
    다름이 아니고 웹페이지에서는 사용자를 추가하면 db에 추가가 되는데
    앱에서 실행시 name과 country를 입력후 insert를 누르면
    <html> <body> <form action="" method="POST"> ....가 나오면서 html코딩했던 부분이 나옵니다. 혹시 왜 이러는 건지 알수 있을까요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.22 22:09 신고

      포스트에 php 코드가 두 개입니다. 그 중에 안드로이드 용인 두 번째 php 코드를 사용해야 합니다.

    • BlogIcon jongha 2020.07.22 22:19

      한가지만 더 물어봐도 될까요??
      php코드가 2개가 있어서 2개 각각 데스크탑에서 실행시켜보면은 잘 작동합니다만,, 스마트폰에서 어플로 말고 주소를쳐서 들어갈때 안드로이드 용인 두번째 php가 실행되지 않고 빈 화면으로만 뜹니다.. 그리고 어플로 실행했을때 insert를 누르면 아무 변화도 없고 어떤 메세지도 뜨지 않으며 아무것도 처리가 안되는것 같습니다... 제가 어느 부분을 놓치고 있는걸까요? ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.22 22:21 신고

      2번째 껀 앱에서 사용하려구 일부 출력을 막아놓은 겁니다. 그래서 안드로이드 앱에서도 일부 출력이 안됩니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.22 22:22 신고

      안드로이드 플랫폼이란 걸 인식하면 출력 안돠게 한거라 안드로이드웹브라우저에서도 안보이는 겁니다

    • BlogIcon jongha 2020.07.22 22:23

      두번째 php파일에서 코드 한줄을 놓쳤었네요 어플에서 드디어 insert가 가능하네요!! 빠른답변 정말 감사합니다. 번창하시길 바랄게요!! 감사합니다.

  10. wjsghwns 2020.07.31 15:33

    안녕하세요, 모든 방법 그대로 따라하고 앱에서 데이터를 입력해서 접근 하려고 하는데, 데이터 입력 액티비티에서 이런 에러가 뜹니다.
    Error: socket failed: EPERM (Operation not permitted)
    검색해본 결과 앱을 지웠다가 다시 깔면 고쳐지는 에러라고 해서 그렇게도 했는데, 역시나 같은 에러가 뜨더라고요. 참고로 아이피는 말씀하신대로 10.0.2.2로 하였습니다.
    뭐가 문제인지 말씀해주시면 정말 감사하겠습니다ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.31 18:50 신고

      다음 링크에 있는 방법을 하나씩 적용해보세요

      https://stackoverflow.com/questions/56266801/java-net-socketexception-socket-failed-eperm-operation-not-permitted

    • BlogIcon wjsghwns 2020.08.04 15:12

      그 방법을 적용해도 에러가 그대로네요. 제가 혹시나 놓친 코드가 있어서 그렇게 나오는걸까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.04 18:29 신고

      혹시 에뮬레이터에서 진행중이라면 폰에서 해보셨나욫

    • BlogIcon wjsghwns 2020.08.10 11:00

      이제 에러없이 작동이 되는데, 막상 MySQL DB를 확인해보면 입력한 데이터가 안뜹니다. php 쪽으로 통해서 컴퓨터로 입력하면 데이터 입력이 되는데 왜 에뮬레이터에서는 안되는걸까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.10 12:15 신고

      안드로이드폰에서 웹브라우저로 데이터가 입력되나 보세요.에뮬레이터에서 PC에 접근 못해서 일수 있습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.12 10:49 신고

      모바일과 PC가 같은 네트워크를 사용해야합니나

    • BlogIcon wjsghwns 2020.08.12 13:13

      에뮬레이터가 아닌 직접 안드로이드 폰을 쓰는 경우에는 아이피 주소를 컴퓨터가 사용하는 아이피 주소와 동일한걸로 맞추고 해줘야 하나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.12 14:01 신고

      혹시 윈도우라면 아래 포스트 14번부터 참고하세요
      https://webnautes.tistory.com/1206

    • BlogIcon wjsghwns 2020.08.12 14:35

      그거 역시 참조하였고 제가 여쭤보던건 에뮬레이터 사용시에 코드에 적는 아이피 주소 말하는거라서요, 10.0.2.2라고 작성해주었었는데 그걸 폰에서 앱을 통해 접근할 경우에는 10.0.2.2 대신에 네트워크 공유기의 아이피 주소를 작성해주나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.12 14:39 신고

      에뮬레이터 사용시에는 10.0.2.2가 맞습니다.최근에 이 아이피가 바뀌었을리는 없을듯합니다.공유기를 사용하는 다른 피시나 실제 스마트폰에서 아파치웹서버 접속이 가능한지 테스트해 볼 필요가 있어보입니다

    • BlogIcon wjsghwns 2020.08.12 17:18

      번거로우실텐데 죄송합니다. 아이폰 웹브라우저로는 접근이 가능한데 안드로이드에서 웹 브라우저로 접근하면 아예 이름이나 나라 입력 창이 안뜨고 빈 창으로 나옵니다. 뭐가 문제인지 도와주시면 정말 감사하겠습니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.12 17:27 신고

      insert.php에서 다음처럼 안드로이드인지 체크하여 그다음줄에 있는 if문에 조건으로 추가했기 때문입니다.

          $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


      안드로이드앱에서 웹 UI가 안보이도록 막은 것입니다.

      바로 위에 있는 php코드와 비교해보세요

      포스트에 php 코드가 2개.있습니다.

      하나는 웹테스트용.. 다른 하나는 안드로이드앱 테스트용

    • BlogIcon wjsghwns 2020.08.13 10:58

      꾸준한 답변 감사합니다. 안드로이드 웹 브라우저에서는 그러면 접근이 가능하다는 뜻인데, 안드로이드 폰에서 앱으로 데이터를 입력하여 전송하려고 시도하면 아무 에러도 뜨지 않고 SQL DB를 확인해도 데이터가 전송되어있지 않는데 뭐가 문제일까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.13 11:01 신고

      포스트와 똑같이 작성해서 문제없이 동작하는지부터 확인해보세요.

  11. Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.12 17:24 신고

    insert.php에서 다음처럼 안드로이드인지 체크하여 그다음줄에 있는 if문에 조건으로 추가했기 때문입니다.

        $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


    안드로이드앱에서 웹 UI가 안보이도록 막은 것입니다.

    바로 위에 있는 php코드와 비교해보세요

    포스트에 php 코드가 2개.있습니다.

    하나는 웹테스트용.. 다른 하나는 안드로이드앱 테스트용

  12. stephen 2020.08.17 17:16

    포스팅 잘 읽었습니다..!
    질문이 하나있는데, 안드로이드 스튜디오에서 실행된 메소드안의 변수에 저장된 값을 DB에 insert 할 수 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.17 17:18 신고

      해당 메서드에서 InsertData를 실행하면 될듯합니다

    • BlogIcon stephen 2020.08.19 15:15

      변수의 자료형이 상이한경우 따로 doInBackground에 선언을 해주어야하나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.19 16:06 신고

      자료형을 문자열로 통일하는게 좋을듯합니다

    • BlogIcon stephen 2020.08.19 16:36

      조금 더 자세히 말씀드리면, GPS 위도 경도값을 받아와서 DB에 저장하는 앱을 만들고있습니다. 위도와 경도의 자료형은 double형으로 고정이라고알고있는데 문자열로 바꾸는 방법이 있을까요? ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.19 16:38 신고

      다음처럼 하면 됩니다

      double d=12.3;//floating literal is double by default  

      String s=String.valueOf(d);

    • BlogIcon stephen 2020.08.24 14:59

      감사합니다 해결했습니다!

  13. 정소현 2020.08.27 15:32

    안녕하세요!! 게시판을 구현하고 있는 완전 초보자입니다ㅠㅠ
    여기 블로그를 통해 많은 걸 배우고 있습니다!!

    위에 설명하신 대로 똑같이 하여서 작동은 다 되는 상태입니다.
    다름이 아니라 xml 하나를 더 추가하여 activity_main과 activity_write으로 나누고, 버튼을 클릭하면 글쓰기로 넘어갈 수 있도록 버튼을 추가하였습니다.
    그런데 이 상태에서 실행을 하게 되면 빨간 줄은 없는데, 에뮬레이터가 실행되려다가 그냥 다운됩니다ㅠ
    MainActivity의 AsyncTask 부분이 밑줄이 쳐져 있어서 이 부분이 문제인 거 같은데, 도저히 답을 몰라서 말입니다..
    어떻게 수정을 해야 할지 알려주시면 감사하겠습니다.

    로그캣에는 다음과 같이 떴습니다.
    2020-08-27 13:53:00.058 7286-7371/? W/ConnectionTracker: Exception thrown while unbinding
    java.lang.IllegalArgumentException: Service not registered: lq@22ea9cf
    at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1624)
    at android.app.ContextImpl.unbindService(ContextImpl.java:1719)
    at android.content.ContextWrapper.unbindService(ContextWrapper.java:717)
    at cg.b(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):1)
    at cg.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    at lr.A(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):10)
    at lc.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at dz.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at iy.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    2020-08-27 13:53:04.077 8146-8146/? I/FA: App measurement is starting up, version: 11020
    2020-08-27 13:53:04.077 8146-8146/? I/FA: To enable debug logging run: adb shell setprop log.tag.FA VERBOSE
    2020-08-27 13:53:04.087 8146-8146/? I/FA: To enable faster debug mode event logging run:
    adb shell setprop debug.firebase.analytics.app com.lge.cloudhub
    2020-08-27 14:02:52.712 8833-8852/? I/FA: App measurement initialized, version: 21028
    2020-08-27 14:02:52.712 8833-8852/? I/FA: To enable debug logging run: adb shell setprop log.tag.FA VERBOSE
    2020-08-27 14:02:52.712 8833-8852/? I/FA: To enable faster debug mode event logging run:
    adb shell setprop debug.firebase.analytics.app com.skt.skaf.OA00018282
    2020-08-27 14:19:28.635 3974-9300/? I/PairHttpConnection: [Upload] Connected
    2020-08-27 14:19:29.065 3974-9286/? E/PairHttpConnection: S3 request >16K, might fail (size=23223) http://b/15866117
    2020-08-27 14:19:31.370 9331-9420/? I/FA: App measurement initialized, version: 28007
    2020-08-27 14:19:31.370 9331-9420/? I/FA: To enable debug logging run: adb shell setprop log.tag.FA VERBOSE
    2020-08-27 14:19:31.371 9331-9420/? I/FA: To enable faster debug mode event logging run:
    adb shell setprop debug.firebase.analytics.app com.google.android.apps.tachyon
    2020-08-27 14:19:36.518 9331-9420/? W/ConnectionTracker: Exception thrown while unbinding
    java.lang.IllegalArgumentException: Service not registered: lq@86fb5fb
    at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1624)
    at android.app.ContextImpl.unbindService(ContextImpl.java:1719)
    at android.content.ContextWrapper.unbindService(ContextWrapper.java:717)
    at cg.b(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):1)
    at cg.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    at lr.A(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):10)
    at lc.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at dz.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at iy.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    2020-08-27 14:56:19.505 3974-10449/? W/ConnectionTracker: Exception thrown while unbinding
    java.lang.IllegalArgumentException: Service not registered: lq@8fbf92b
    at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1624)
    at android.app.ContextImpl.unbindService(ContextImpl.java:1719)
    at android.content.ContextWrapper.unbindService(ContextWrapper.java:717)
    at cg.b(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):1)
    at cg.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    at lr.A(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):10)
    at lc.a(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at dz.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):3)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at iy.run(:com.google.android.gms.dynamite_measurementdynamite@202175065@20.21.75 (100400-0):6)
    2020-08-27 14:57:16.023 3974-3974/? E/FirebaseInstanceId: binding to the service failed
    2020-08-27 15:19:57.237 3320-9708/? W/FA-SVC: Interrupted in onRunTask while uploading

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.27 20:44 신고

      정확한 원인은 알 수 없지만 Serivce와 관련있는 듯합니다.

      아래 링크와 관련있으려나요?
      http://www.masterqna.com/android/81194/service-unbind-%ED%95%A0-%EB%95%8C-exception-%EC%9D%B4-%EB%82%98%EC%9A%94

  14. dasdas 2020.09.14 22:58

    안녕하세요. 블로그 잘 보고 있습니다.
    maria DB에서
    mySQL로 invert default 를 눌러 sql로 변경하였습니다.

    그래도 사이트 주소를 들어가면 Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'webnautes'@'localhost' (using password: YES)
    오류가 뜹니다.
    혹시 무슨 문제가 있는것일까요 ?
    위에서는 잘 따라했습니다..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.14 23:01 신고

      webnautes가 아니라 사용하는 아이디로 바꿔야하는데 안바꾼 부분이 있어보이네요

  15. 맹디 2020.09.14 23:19

    안녕하세요!
    유튜브 강좌랑 다른 블로그 자료 보면서 회원가입 구현하다가 며칠동안 삽질했는데.. 한 10분만에 성공했어요.. 이 블로그 덕분에..
    그래서 무슨 블로그인가 봤는데 멈춤보다 천천히라도...
    매번 프로젝트 할 때마다 도움 정말 많이 받고 있습니다!!
    원래 댓글 잘 안남기는데 항상 도움 잘 받고 있어서 댓글 남깁니다!! 복 많이 받으세요 :->

  16. dasdas 2020.09.15 10:54

    php파일에 아이디패스워드 수정하기위해 복사했는데
    수정본이 제대로복사가 안됐던거였네요!
    도움주셔서 감사합니다!

  17. dasdas 2020.09.15 10:56

    또 질문 남겨 죄송합니다.
    도움이 많이되서 계속 이쪽에 질문을 하게 되는것같습니다.
    핸드폰과 노트북이 둘 다 같은 와이파이에 연결이 되어있는데
    Error:failed to connect to/10.0.2.2(port 80)from ~~~ 이런식으로의 오류가 뜹니다.
    무슨문제가있는걸까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.15 21:12 신고

      다음 글에 있는 "16. 문제 발생시 해결 방법"를 확인해보세요. 윈도우라면 방어벽이 문제일 수 있을듯합니다.

      윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

      http://webnautes.tistory.com/1206

  18. 질문 2020.09.16 23:42

    안녕하세요 . 컬럼을 5개로 늘려서 하고싶은데 컬럼을 5개로 늘리면 웹상에서는 되는데 안드로이드랑 연결하면 자꾸 앱이 중지됩니다 ㅠㅠ 혹시 컬럼을 추가하여 하고 싶으면 어느 부분을 수정해야하나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.17 20:54 신고

      다음 부분만 개수랑 변수 이름을 웹하고 맞추세요
      포스트에 있는 php코드와 아래 코드를 비교해보고 진행해보세요

      String name = (String)params[1];
      String country = (String)params[2];

      String serverURL = (String)params[0];
      String postParameters = "name=" + name + "&country=" + country;

  19. qweew 2020.09.18 13:59

    안녕하세요. 따라하다가 질문있어 댓글남깁니다.
    안드로이드에 연결하려고, 코드 수정하였고
    방어벽에 대한 설정들을 다 해결했습니다.

    insert를 눌러도 새로운 사용자를 추가했습니다
    라는 문구가 안뜨는데 무슨 문제가있는걸까요 ?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.18 22:10 신고

      안드로이드의 웹브라우저에서 확인해보세요.

      3번에 있는 PHP코드를 사용해야 합니다.

  20. 감사합니다 2020.09.22 20:57

    안녕하세요 블로그보며 독학중인 학생입니다

    다른 내용도 보고 이번 내용을 보다가 4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다 부분에서

    안드로이드 스튜디오로 복붙을 하면 오류가 상당히 많이 생깁니다... 이게 버전이 달라서 생기는 오류일까요
    맨처음에 자바 코드가 보인다며 코틀린으로 자동 번역을 해준다길래 그걸 해봐도 오류가 많이 생기더군요....

    public class MainActivity extends AppCompatActivity {
    이줄 아래부터는 쭉 빨간색으로 표기가 되는데 혹시 복붙하면서 생기는 오류일까요...?

  21. 홍민아 2020.10.23 00:21

    안녕하세요 블로그 포스팅이 많은 도움이 되었습니다! 다름이 아니라 본 코드로 시행을 하던 중 막히는 부분이 있어 질문드립니다. 현재 aws 상에서 실행을 하고 있는데 dbcon.php부터 SQLSTATE[HY000] [2002] No such file or directory 다음과 같은 오류가 발생합니다. aws상에서 PDO를 이용할 수 없는 문제 같은데 혹시 해결방안이 있을지 여쭙니다.

+ Recent posts