안드로이드 앱이 PHP 프로그램을 매개로 하여 MySQL 데이터베이스 서버에 데이터를 저장하는 간단한 예제입니다.
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)를 설치합니다.
오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 PHP > Version을 선택합니다.
사용가능한 PHP 버전이 보이는 데 최신 버전인 7.2.18를 선택합니다. 글 작성시점과 버전이 다를 수 있습니다.
1-2. Ubuntu
다음 포스팅을 참고하여 Ubuntu에 LAMP( Apache2, MySQL , PHP7)를 설치합니다.
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을 사용한다면 같은 상황이 있을 수 있습니다.
sudo 명령시 입력하는 사용자 암호 입력으로 기존 로그인을 대체합니다.
2-4. 윈도우와 우분투에서 동일하게 진행하는 부분입니다.
데이터베이스를 생성합니다.
새로 생성한 데이터베이스를 사용할 사용자를 생성합니다.
앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.
quit를 입력하여 MySQL 콘솔을 종료합니다.
2-5. MySQL 콘솔에 새로 생성한 사용자로 접속합니다.
우분투에서는 다음처럼 MySQL 로그인을 합니다. 사용자 이름은 새로 생성한 데이터베이스 접근권한을 가진 사용자 입니다.
Enter password: 에 사용자의 암호를 입력해줍니다.
윈도우에서는 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다.
새로 생성한 데이터베이스 접근권한을 가진 사용자 이름을 적고 OK 버튼을 클릭합니다.
Enter password: 메시지가 보이면 사용자의 암호를 입력해줍니다.
2-6. 데이터베이스 testdb에 필요한 테이블 person을 생성하고 MySQL이 잘 동작하는지 여부를 다음처럼 확인합니다.
3. 웹브라우저로 PHP 동작 테스트
Android 앱으로 테스트를 진행하기 전에 다음 PHP 코드를 웹 브라우저로 간단한 테스트를 해보겠습니다.
다음 두 개의 파일이 필요합니다.
dbcon.php
MySQL 서버 접속을 위해 사용되는 코드입니다.
insert.php
지정해 높은 데이터베이스의 테이블에 데이터를 저장하기 위해 사용됩니다.
dbcon.php
insert.php
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번부터 참고하세요.
3-5. MySQL에서 확인해보면 데이터가 정상적으로 입력된 것을 볼 수 있습니다.
SELECT 문으로 testdb 데이터베이스에 있는 Person 테이블의 내용을 조회합니다.
웹에서 입력한 이름과 주소가 제대로 입력되었는지 확인가능합니다.
4. Android 앱에서 테스트
웹서버의 PHP 파일을 통해 데이터베이스에 데이터를 저장하는 안드로이드 앱을 작성합니다.
4-1. insert.php 파일을 다음 코드로 변경합니다.
4-2. AndroidManifest.xml 매니페스트 파일의 manifest 태그 하위 항목으로 인터넷 접근 허용 퍼미션을 추가합니다.
android 9.0 이상에서 동작하게 하려면 usesCleartextTraffic 옵션도 추가해야 합니다. 해주지 않으면 “cleartext http traffic to not permitted” 라는 에러가 발생합니다.
4-3. activity_main.xml 레이아웃 파일을 아래 내용으로 바꿉니다.
4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다.
다음 줄에 있는 IP 주소를 아파치 웹서버가 설치된 컴퓨터의 IP로 수정하세요.
private static String IP_ADDRESS = "IP주소";
안드로이드 에뮬레이터와 서버가 같은 컴퓨터에 동작하는 경우에는 다음 아이피를 입력합니다.
Android Studio의 에뮬레이터 - 10.0.2.2
GenyMotion - 192.168.56.1
4-5. 안드로이드 프로젝트를 빌드하여 앱을 테스트할 디바이스 또는 에뮬레이터에 설치합니다.
앱을 실행시키면 다음과 같은 화면이 보입니다.
테스트 문자열을 입력하고 INSERT를 터치합니다.
성공한 경우 SQL문 처리 성공이라는 메시지가 보이게 됩니다.
Error: connect timed out 메시지가 보인다면 본 포스트의 3-4를 다시 확인해보세요.
방어벽 문제 일 수 있습니다.
4-6. MySQL에서 확인해보면 정상적으로 입력된 것을 볼 수 있습니다.
5. 코드 설명
다음 두 단계를 거쳐서 안드로이드 앱의 데이터가 MySQL 서버에 저장됩니다.
안드로이드 앱에서 POST 방식으로 PHP 코드에 데이터를 전달합니다.
PHP 코드에서 MySQL 서버에 접속하여 전달받은 데이터를 저장합니다.
우선 안드로이드 앱 코드를 살펴보겠습니다.
PHP 코드를 보겠습니다.
6. 관련 포스팅
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
'Android > Android PHP MySQL 예제' 카테고리의 다른 글
Android PHP MySQL 예제 - 데이터베이스에 데이터 입력하기 (622) | 2020.07.14 |
---|---|
Android PHP MySQL 예제 - 데이터베이스에 데이터 저장 및 JSON 형식으로 가져오는 예제 프로젝트 (100) | 2019.11.17 |
Android PHP MySQL 예제 - 데이터베이스 질의(query) 결과 출력하기 (102) | 2019.11.17 |
Android PHP MySQL 예제 - 데이터베이스에서 데이터를 JSON 형식으로 가져오기 (554) | 2019.11.17 |
Android에서 MSSQL DB 내용을 읽어와서 LIstview에 출력하기 (49) | 2015.09.15 |
포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.
여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다.
감사합니다 : )
유튜브 구독하기
제가 쓴 책도 한번 검토해보세요.
- 이전 댓글 더보기
-
익듀 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
다양한 방법으로 시도 중 인데 혹시 알고있는 오류인가요 ? -
sunrise 2020.06.18 01:51
mAdapter = new UsersAdapter(this, mArrayList);
PersonalData personalData = new PersonalData();
이 부분에서 Type parameter cannot be instantiated dilectly 라며 빨간줄이 생깁니다.
어떻게 해결해야 할까요? -
dbmaker 2020.06.23 15:14
Deprecated: Function get_magic_quotes_gpc() is deprecated in C:\Apache24\htdocs\dbcon.php on line 23
라고 뜨는데 혹시
코드를 어떻게 수정해야하는지 알려주실 수 있나요?-
해당 함수가 나중에 제거될수 있다는 메시지입니다. 에러는 아니고 지금 실행하는데에도 문제가 되지는 않지만 나중을 생각하면 해당 함수가 대체되는 함수를 찾아봐야 할듯합니다.
찾아보니 다음처럼 대체하라고 하네요
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
-
-
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 지정이 다 돼 있는데도 이 문제가 계속 발생하네요.... -
안드로이드 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);
?>
-
꾸준한 답변 감사드립니다~~~
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;
?>
-
jongha 2020.07.22 22:08
포스팅 하시느라 고생많으셨습니다.
다름이 아니고 웹페이지에서는 사용자를 추가하면 db에 추가가 되는데
앱에서 실행시 name과 country를 입력후 insert를 누르면
<html> <body> <form action="" method="POST"> ....가 나오면서 html코딩했던 부분이 나옵니다. 혹시 왜 이러는 건지 알수 있을까요?? -
wjsghwns 2020.07.31 15:33
안녕하세요, 모든 방법 그대로 따라하고 앱에서 데이터를 입력해서 접근 하려고 하는데, 데이터 입력 액티비티에서 이런 에러가 뜹니다.
Error: socket failed: EPERM (Operation not permitted)
검색해본 결과 앱을 지웠다가 다시 깔면 고쳐지는 에러라고 해서 그렇게도 했는데, 역시나 같은 에러가 뜨더라고요. 참고로 아이피는 말씀하신대로 10.0.2.2로 하였습니다.
뭐가 문제인지 말씀해주시면 정말 감사하겠습니다ㅠㅠ -
stephen 2020.08.17 17:16
포스팅 잘 읽었습니다..!
질문이 하나있는데, 안드로이드 스튜디오에서 실행된 메소드안의 변수에 저장된 값을 DB에 insert 할 수 있을까요? -
정소현 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 -
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)
오류가 뜹니다.
혹시 무슨 문제가 있는것일까요 ?
위에서는 잘 따라했습니다..
-
맹디 2020.09.14 23:19
안녕하세요!
유튜브 강좌랑 다른 블로그 자료 보면서 회원가입 구현하다가 며칠동안 삽질했는데.. 한 10분만에 성공했어요.. 이 블로그 덕분에..
그래서 무슨 블로그인가 봤는데 멈춤보다 천천히라도...
매번 프로젝트 할 때마다 도움 정말 많이 받고 있습니다!!
원래 댓글 잘 안남기는데 항상 도움 잘 받고 있어서 댓글 남깁니다!! 복 많이 받으세요 :-> -
dasdas 2020.09.15 10:54
php파일에 아이디패스워드 수정하기위해 복사했는데
수정본이 제대로복사가 안됐던거였네요!
도움주셔서 감사합니다! -
dasdas 2020.09.15 10:56
또 질문 남겨 죄송합니다.
도움이 많이되서 계속 이쪽에 질문을 하게 되는것같습니다.
핸드폰과 노트북이 둘 다 같은 와이파이에 연결이 되어있는데
Error:failed to connect to/10.0.2.2(port 80)from ~~~ 이런식으로의 오류가 뜹니다.
무슨문제가있는걸까요? -
질문 2020.09.16 23:42
안녕하세요 . 컬럼을 5개로 늘려서 하고싶은데 컬럼을 5개로 늘리면 웹상에서는 되는데 안드로이드랑 연결하면 자꾸 앱이 중지됩니다 ㅠㅠ 혹시 컬럼을 추가하여 하고 싶으면 어느 부분을 수정해야하나요?
-
qweew 2020.09.18 13:59
안녕하세요. 따라하다가 질문있어 댓글남깁니다.
안드로이드에 연결하려고, 코드 수정하였고
방어벽에 대한 설정들을 다 해결했습니다.
insert를 눌러도 새로운 사용자를 추가했습니다
라는 문구가 안뜨는데 무슨 문제가있는걸까요 ? -
감사합니다 2020.09.22 20:57
안녕하세요 블로그보며 독학중인 학생입니다
다른 내용도 보고 이번 내용을 보다가 4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다 부분에서
안드로이드 스튜디오로 복붙을 하면 오류가 상당히 많이 생깁니다... 이게 버전이 달라서 생기는 오류일까요
맨처음에 자바 코드가 보인다며 코틀린으로 자동 번역을 해준다길래 그걸 해봐도 오류가 많이 생기더군요....
public class MainActivity extends AppCompatActivity {
이줄 아래부터는 쭉 빨간색으로 표기가 되는데 혹시 복붙하면서 생기는 오류일까요...?