SlideShare a Scribd company logo
1 of 46
Download to read offline
[Live Coding] (1/23 토) 
Fast Campus 안드로이드 앱 개발 입문 4기
Live Coding - Camp_WebBrowser
작성자: 하동욱 (​https://fb.com/mindwing​)
이 강의노트는 ​https://goo.gl/rxb2JF​ 에서 보실 수 있습니다.
 
목차 
0) 들어가기에 앞서 
1) Android Studio 기동해서 새 프로젝트 만들기 
2) 실행해보기 
3) Action Bar 숨기기 
4) 기본 UI 만들고 이벤트 핸들링 코딩해보기 
5) WebView 를 써보자 
6) Back, Forward 버튼 붙이기 
7) Design Support Library 를 이용하여 Snackbar 써보기 
8) github 에서 프로젝트를 clone 하기 
 
● 0) 들어가기에 앞서 
○ Live Coding 은 처음부터 앱의 완성까지 직접 코드를 손수 짜보는 과정입니다. 
○ Android SDK 는 23 버전을 사용하므로, 반드시 버전을 확인하시기 바랍니다. 
 
   
○ File > Settings... > Appearance & Behavior > System Settings > Android SDK 
의 SDK Platforms 탭에서 Android 6.0 (Marshmallow) 가 설치되어 있어야 
합니다. (API 23) 
 
 
○ File > Settings... > Appearance & Behavior > System Settings > Android SDK 
의 SDK Tools 탭에서 Android Support Library 와 Android Support Repository 
가 설치되어 있어야 합니다. 
 
 
● 1) Android Studio 기동해서 새 프로젝트 만들기 
○ 다음과 같이 Android 초기메뉴에서 새 프로젝트를 만들기 메뉴를 선택합니다. 
■ 혹은, 이미 Android Studio 를 기동중이라면 File > New > New 
Project... 메뉴를 선택합니다. 
 
 
 
 
 
 
○ 다음과 같이 Application 에 WebBrowser 를 입력하고, Company Name 에는 
여러분들의 적절한 도메인을 적어주면 됩니다. 
■ 저는 mindwing.kr 로 적었습니다. 도메인 이름과 Application 이름은 
합쳐져서 Package name 으로 표현되는데, 이 이름은 Google Play 
스토어내에서 이 앱을 유일하게 구별하는 이름표 역할을 하므로, 
스토어에 올릴 앱을 만들 때에는 신중하게 결정해야 합니다. 
 
 
 
○ 이제 다음 단계는 지원단말을 결정하는 메뉴입니다. Google 권장사항인 API 
15 를 최저지원 API 로 삼으면 Google Play 스토어에 접속하는전세계의 
Android 단말중에서 96.2% 의 이용자들을 대상으로 할 수 있으므로, 그대로 
따릅니다. 
■ 나머지 3.8% 의 단말은 API 14 이하인 단말들입니다. 이 단말들은 
사용률이 너무 낮고 단말자체도 사용자가 잘 사용하지 않을 가능성이 
높습니다. 이런 단말들은 과감하게 지원하지 않도록 하는 것이 
문제발생소지를 없애는 길입니다. 
 
 
 
○ 이제 Activity 를 자동으로 만들어주길 원하는지 물어보는 화면입니다. 빈 
Activity 가 하나 있으면 되므로, Empty Activity 를 선택합니다. 
■ Blank Activity 는 Floating Action Button 이 추가되므로 필요한 
경우에만 사용합니다. 
■ 수동으로 Activity 를 추가하려 한다면 "Add No Activity” 를 선택합니다. 
 
 
 
 
○ 마지막으로 Activity 의 이름과 layout xml 파일 이름을 정하는 화면이며, 
Android 가 제시하는 기본값을 그대로 사용합니다. 
 
 
 
○ 프로젝트가 막 생성되었을 때에는 빌드와 내부 인덱싱 작업도 시작됩니다. 이 
과정은 부하가 꽤 걸리기 때문에, 특히 램이 부족하거나 SSD 가 아닌 HDD 를 
장착한 경우에는 잠시동안 아무 작업도 하지 말고 가만히 내버려두시기 
바랍니다. 
■ 빌드가 완료되어야 리소스 관련 클래스인 R 을 사용할 수 있게 됩니다. 
■ 모든 백그라운드 작업이 끝나고 빨간색 에러표시도 없이 깨끗한 상태가 
될 때까지 기다려주세요. 
 
 
 
 
○ 위 이미지와 같이 되셨나요? 
 
 
 
 
○ 이렇게 되셨다면 위 이미지와 같이 XML 아이콘을 누른 다음 activity_main.xml 
파일을 선택해서 열어보겠습니다. 
 
 
 
 
 
○ 만약, activity_main.xml 파일을 열었을 때에 위 이미지처럼 Rendering Problem 
이 발생한다면 API 23 대신 API 22 를 선택했다가 다시 API 23 을 
선택해주세요. 그래도 문제가 있다면 화살표 모양의 동그라미 refresh 버튼을 
눌러주세요. 
■ 문제가 해결되지 않는다면 말씀해주세요. 개별적으로 
수정해드리겠습니다. 
■ 이 문제는 Android Studio 와 Gradle 빌드시스템이 서로 독립적으로 
실행되다가 서로 약간 동기화가 되지 못하는 버그때문입니다. 
그러므로, 프로젝트를 새로 생성하는 등의 Android Studio 가 바쁘게 
움직일 때에는 별도의 작업을 시키지 말고 가만 놔두시는 것이 
좋습니다. (안정화버전이 나오리라 기대합니다.) 
 
 
 
○ 문제가 해결되었습니다. (문제가 해결되지 않은 분들은 제가 개별적으로 
해결해드리겠습니다.) 
 
○ 이제 코딩타임입니다. 
   
○ 2) 실행해보기 
○ Android Studio 가 마련해준 프로젝트 형상을 그대로 실행해봅니다. 
■ 초록색 화살표 아이콘을 누르면 앱이 실행됩니다. 
 
 
 
○ 이 문서에서는 에뮬레이터에서 개발해보겠지만, 개발하려는 앱의 덩치가 
크거나, 단말이 존재하지 않는 특정 API level 을 테스트해야 하거나, 램이 
넉넉하지 않은 개발환경에서는 에뮬레이터를 쓰는 것이 무척 힘든 일이므로, 
직접 단말기를 연결해서 개발하는 것을 권장합니다. 
■ i7 쿼드코어에 램 8GB 라면 도전해보세요. 
 
 
 
○ 다음은 WebBrowser 앱이 실행되어서 MainActivity 가 보여지는 모습입니다. 
   
○ 3) Action Bar 숨기기 
○ Android Studio 가 기본으로 만들어준 UI 에는 ActionBar 가 포함되어 
있습니다. 
○ 이 예제에서는 ActionBar 를 쓰지 않을 것이므로, 이를 숨기겠습니다. 
■ ActionBar 는 테마에 속하는 부분이므로 테마를 수정해야 합니다. 
○ 다음 이미지처럼 app > res > values > styles.xml 파일을 엽니다. 
 
 
 
○ 위 이미지처럼 4번째 줄에 "Theme.AppCompat.Light.” 이라고 되어 있는 부분 
뒤에 있는 “DarkActionBar” 를 지우고 점이 있는 부분에 커서를 위치시킨 다음 
ctrl ­ space 키를 누릅니다. 
■ "Theme.AppCompat.Light.NoActionBar" 를 선택합니다. 
● NoActionBar 테마를 이용하도록 수정하는 것입니다. 
 
[res/values/styles.xml] 
<resources> 
 
   ​<!­­ Base application theme. ­­> 
   ​<style ​name=​"AppTheme" ​parent=​"​Theme.AppCompat.Light.NoActionBa​r​"​> 
       ​<!­­ Customize your theme here. ­­> 
       ​<item ​name=​"colorPrimary"​>​@color/colorPrimary​</item> 
       <item ​name=​"colorPrimaryDark"​>​@color/colorPrimaryDark​</item> 
       <item ​name=​"colorAccent"​>​@color/colorAccent​</item> 
   </style> 
 
</resources> 
 
 
○ 이제 다음 이미지처럼 NoActionBar 로 변경되었습니다. 
○ Android Studio 2.0 을 실행중이라면 코드를 수정 후 실행아이콘에 번개모양이 
나오는 것을 볼 수 있습니다. 
■ Instant Run 이라는 기능으로 코드를 수정한 다음 apk 를 다시 만들어서 
단말이나 에뮬레이터에 인스톨하고 다시 앱을 실행하는 복잡한 과정을 
거치지 않고, 현재 실행되어 있는 앱에서 변경된Activity 만 바꿔주는 
기능입니다. 
■ 개발속도를 빠르게 가져갈 수 있는 Android Studio 2.0 의 새로운 
기능입니다. 
 
 
 
 
○ 다음 그림은 Action Bar 가 사라진 모습입니다. 
■ Instant Run 이 적용되었을 경우 안내 Toast 가 떠서 이를 알 수 있게 
해줍니다. 
 
 
 
 
○ 참고로, 테마를 바꾸지 않고 직접 코드상에서 Action Bar 를 없앨 수도 
있습니다. 
■ 다음처럼 hideActionBar() 메서드를 작성합니다. 
■ onCreate() 메서드에서 hideActionBar() 메서드를  호출해서 앱이 
기동되자마자 ActionBar 를 숨길 수 있도록 합니다. 
○ 이 예제는 ​SDK 23​ 버전을 사용하므로, 이전 버전으로 작성하면 
hideActionBar() 메서드에 문제가 발생할 수 있습니다. 
 
[MainActivity.java] 
... 
import ​android.support.v7.app.ActionBar​; 
... 
 
public class ​MainActivity ​extends ​AppCompatActivity { 
 
    @Override 
    ​protected void ​onCreate​(Bundle savedInstanceState) { 
     ​   ​super​.onCreate(savedInstanceState)​; 
     ​   ​setContentView(R.layout.​activity_main​)​; 
 
        hideActionBar()​; 
    ​} 
 
    ​private void ​hideActionBar​() { 
   ​    ​ ​ActionBar actionBar = getSupportActionBar()​; 
    ​    ​actionBar.hide()​; 
    } 
} 
 
 
○ 이번 강의에서는 코드에서 변경하는 방법 대신 테마를 변경하는 방법을 
이용하니, 이 방법은 참고로만 알아두세요. 
 
   
○ 4) 기본 UI 만들고 이벤트 핸들링 코딩해보기  
○ 웹브라우저에는 기본적으로 URL 을 입력받는 창과 웹화면이 보이는 부분이 
있습니다. 
■ URL 을 입력받기 위해서는 EditText 컴포넌트를 이용하며, 웹화면을 
보여주기 위해 WebView 컴포넌트를 이용합니다. 
■ 웹페이지의 실질적인 처리는 모두 WebView 컴포넌트가 담당하므로, 
웹브라우저 앱을 만들기 위해서는 WebView 컴포넌트만 잘 다룰 수 
있으면 됩니다. 
○ 아래 코드는 MainActivity 에서 사용하는 UI 레이아웃입니다. 
■ <RelativeLayout> 으로 전체를 레이아웃합니다. 
■ 그 내부에 <EditText> 와 <WebView> 가 포함됩니다. 
■ 각각의 ID는 ​text_url​ 과 ​webview​ 이며, 이는 Java 코드에서 사용할 
이름이 됩니다. 
 
[res/layout/activity_main.xml] 
<?​xml version=​"1.0" ​encoding=​"utf­8"​?> 
<RelativeLayout 
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​:paddingBottom=​"@dimen/activity_vertical_margin" 
   ​android​:paddingLeft=​"@dimen/activity_horizontal_margin" 
   ​android​:paddingRight=​"@dimen/activity_horizontal_margin" 
   ​android​:paddingTop=​"@dimen/activity_vertical_margin" 
   ​tools​:context=​"kr.mindwing.webbrowser.MainActivity"​> 
 
   <EditText 
       ​android​:id=​"@+id/​text_url​" 
       ​android​:layout_width=​"match_parent" 
       ​android​:layout_height=​"wrap_content" 
       ​android​:singleLine=​"true" ​/> 
 
   <WebView 
       ​android​:id=​"@+id/​webview​" 
       ​android​:layout_width=​"match_parent" 
       ​android​:layout_height=​"match_parent" 
       ​android​:layout_below=​"@id/text_url" /​> 
 
</RelativeLayout> 
 
 
○ 이제 URL 을 입력받아서 Toast 로 띄워보는 Java 코드를 짜보겠습니다. 
■ 기본적인 이벤트 핸들링을 하는 방법을 통해서 Toast 를 띄웁니다. 
package ​kr.mindwing.webbrowser​; 
 
import ​android.os.Bundle​; 
import ​android.support.v7.app.AppCompatActivity​; 
import ​android.view.KeyEvent​; 
import ​android.view.View​; 
import ​android.widget.EditText​; 
import ​android.widget.Toast​; 
 
public class ​MainActivity ​extends ​AppCompatActivity { 
 
   ​private ​EditText ​textUrl​; 
   private ​View.OnKeyListener ​listener ​= ​new ​View.OnKeyListener() { 
 
       ​@Override 
       ​public boolean ​onKey​(View v​, int ​keyCode​, ​KeyEvent event) { 
           ​if ​(event.getAction() != KeyEvent.​ACTION_DOWN​) { 
               ​return false; 
           ​} 
 
           ​boolean ​processed = ​false; 
 
           switch ​(keyCode) { 
               ​case ​KeyEvent.​KEYCODE_ENTER​: 
                   Toast.​makeText​( 
                           MainActivity.​this, 
                           ​textUrl​.getText().toString()​, ​Toast.​LENGTH_SHORT​).show()​; 
 
                   ​processed = ​true; 
                   break; 
 
               default​: 
                   ​break; 
           ​} 
 
           ​return ​processed​; 
       ​} 
   }​; 
 
   ​@Override 
   ​protected void ​onCreate​(Bundle savedInstanceState) { 
       ​super​.onCreate(savedInstanceState)​; 
       ​setContentView(R.layout.​activity_main​)​; 
       ​setupUI()​; 
   ​} 
 
   ​private void ​setupUI​() { 
       ​textUrl ​= (EditText) findViewById(R.id.​text_url​)​; 
       ​textUrl​.setOnKeyListener(​listener​)​; 
   ​} 
} 
 
 
○ TextView 영역에 “camp android” 라고 입력하고서 엔터키를 누르면, 이벤트가 
Java 코드의 ​OnKeyListener​ 객체에게 전달되어 Toast 를 띄우는 코드를 
실행하게 됩니다. 
 
○ 5) WebView 를 써보자 
○ android.webkit.WebView 클래스는 웹페이지를 다루는 기능을 가지고 
있습니다. 
■ 웹페이지의 URL 만 지정해주면 알아서 웹서버에 접속해서 필요한 
파일들을 다운로드받아서 표시해줍니다. 
○ 문자열을 입력받아서 Toast 를 띄웠던 이전 코드를 수정해서 웹페이지의 URL 
을 입력받은 다음, 이를 WebView 객체에게 전달해보겠습니다. 
■ XML 로 된 UI 코드에서 이미 TextView 와 더불어 WebView 객체도 
생성되도록 지정되어 있습니다. 
 
[MainActivity.java] 
package ​kr.mindwing.webbrowser​; 
 
import ​android.os.Bundle​; 
import ​android.support.v7.app.AppCompatActivity​; 
import ​android.view.KeyEvent​; 
import ​android.view.View​; 
import ​android.webkit.WebView​; 
import ​android.widget.EditText​; 
 
public class ​MainActivity ​extends ​AppCompatActivity { 
 
   ​private ​EditText ​textUrl​; 
   private ​WebView ​webView​; 
   private ​View.OnKeyListener ​listener ​= ​new ​View.OnKeyListener() { 
 
       ​@Override 
       ​public boolean ​onKey​(View v​, int ​keyCode​, ​KeyEvent event) { 
           ​if ​(event.getAction() != KeyEvent.​ACTION_DOWN​) { 
               ​return false; 
           ​} 
 
           ​boolean ​processed = ​false; 
 
           switch ​(keyCode) { 
               ​case ​KeyEvent.​KEYCODE_ENTER​: 
                   ​webView​.loadUrl(​textUrl​.getText().toString())​; 
 
                   ​processed = ​true; 
                   break; 
 
               default​: 
                   ​break; 
           ​} 
 
           ​return ​processed​; 
       ​} 
   }​; 
 
   ​@Override 
   ​protected void ​onCreate​(Bundle savedInstanceState) { 
       ​super​.onCreate(savedInstanceState)​; 
       ​setContentView(R.layout.​activity_main​)​; 
       ​setupUI()​; 
   ​} 
 
   ​private void ​setupUI​() { 
       ​textUrl ​= (EditText) findViewById(R.id.​text_url​)​; 
       ​textUrl​.setOnKeyListener(​listener​)​; 
       ​textUrl​.setText(​"http://facebook.com"​)​; 
 
       ​webView ​= (WebView) findViewById(R.id.​webview​)​; 
   ​} 
} 
 
 
○ TextView 에 기본값으로 “​http://facebook.com​” 을 설정했습니다. 
■ 엔터키만 누르면 바로 페이스북으로 접속할 수 있습니다. 
○ 그런데, 다음 화면과 같은 에러 화면이 떴습니다. 
 
 
 
 
 
○ "android webview ERR_CACHE_MISS” 키워드로 구글링하면 매우 많은 
검색결과가 나오는데, 어느 링크를 눌러봐도 INTERNET 퍼미션이 없어서 
발생하는 문제라는 설명을 하고 있습니다. 
 
 
 
 
○ Internet 퍼미션은 AndroidManifest.xml 에 다음과 같이 적어주면 됩니다. 
■ 퍼미션을 일일이 적어주게 하는 이유는 안드로이드 시스템이 어떤 앱이 
어떤 퍼미션을 이용하는지 내부적으로 추적하고 있어야 하기 
때문입니다. 건물 등기부등본에 시시콜콜한 내용들을 모두 적어두게 
하고 이를 법원이 관리하는 것과 마찬가지입니다. 
 
[app/manifests/AndroidManifest.xml] 
<?​xml version=​"1.0" ​encoding=​"utf­8"​?> 
<manifest ​xmlns:​android​=​"http://schemas.android.com/apk/res/android" 
   ​package=​"kr.mindwing.webbrowser"​> 
 
  ​ <uses­permission ​android​:name=​"android.permission.INTERNET" ​/> 
 
   <application 
       ​android​:allowBackup=​"true" 
       ​android​:icon=​"@mipmap/ic_launcher" 
       ​android​:label=​"@string/app_name" 
       ​android​:supportsRtl=​"true" 
       ​android​:theme=​"@style/AppTheme"​> 
       <activity ​android​:name=​".MainActivity"​> 
           <intent­filter> 
               <action ​android​:name=​"android.intent.action.MAIN" ​/> 
 
               <category ​android​:name=​"android.intent.category.LAUNCHER" ​/> 
           </intent­filter> 
       </activity> 
   </application> 
 
</manifest> 
 
 
○ 이제 문제가 고쳐졌는지 확인해보겠습니다. 
■ 로그인화면이 나오긴 나왔는데, 이것은 지금 만든 WebBrowser 앱이 
아니고, 안드로이드 기본 내장 웹브라우저가 대신 실행된 모습입니다. 
 
 
 
○ 이것은 WebView 가 Facebook 의 redirect 를 처리할 능력이 없어서, 대신 다른 
웹브라우저앱을 띄웠기 때문입니다. 
■ 이 문제를 해결하기 위해서는 WebView 가 기본적인 기능을 처리할 수 
있도록 WebViewClient 객체를 만들어 지정하면 됩니다. 
■ WebViewClient 는 개발자가 추가코드를 적용하여 기능을 확장해서 쓸 
수 있도록 해주기 위한 장치입니다. 
 
[MainActivity.java] 
import ​android.webkit.WebView​; 
import ​android.webkit.WebViewClient​; 
import ​android.widget.EditText​; 
 
... 
    private void ​setupUI​() { 
        ​textUrl ​= (EditText) findViewById(R.id.​text_url​)​; 
        ​textUrl​.setOnKeyListener(​listener​)​; 
        ​textUrl​.setText(​"http://facebook.com"​)​; 
 
        ​webView ​= (WebView) findViewById(R.id.​webview​)​; 
        ​webView.setWebViewClient(​new ​WebViewClient())​; 
    } 
... 
 
 
○ 다시 앱을 실행해보겠습니다. 
■ 이제는 로그인 화면이 WebView 내에서 잘 나오는 것을 볼 수 
있습니다. 
 
   
○ 6) Back, Forward 버튼 붙이기 
○ 이제 기본적인 동작은 하는 것 같은데, 일반적인 웹브라우저와 비교하면 뒤로 
가기와 앞으로 가기 버튼이 없는 것이 눈에 띕니다. 
■ 버튼 2개를 만들고, 이에 대한 이벤트 처리 코드를 작성해보겠습니다. 
 
[activity_main.xml] 
<?​xml version=​"1.0" ​encoding=​"utf­8"​?> 
<RelativeLayout 
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​:paddingBottom=​"@dimen/activity_vertical_margin" 
   ​android​:paddingLeft=​"@dimen/activity_horizontal_margin" 
   ​android​:paddingRight=​"@dimen/activity_horizontal_margin" 
   ​android​:paddingTop=​"@dimen/activity_vertical_margin" 
   ​tools​:context=​"kr.mindwing.webbrowser.MainActivity"​> 
 
   <LinearLayout 
       ​android​:id=​"@+id/upper" 
       ​android​:layout_width=​"match_parent" 
       ​android​:layout_height=​"wrap_content" 
       ​android​:orientation=​"horizontal" 
       ​android​:padding=​"1dp"​> 
 
       <EditText 
           ​android​:id=​"@+id/text_url" 
           ​android​:layout_width=​"0dp" 
           ​android​:layout_height=​"wrap_content" 
           ​android​:layout_weight=​"6" 
           ​android​:singleLine=​"true" ​/> 
 
       <Button 
           ​android​:id=​"@+id/back" 
           ​android​:layout_width=​"0dp" 
           ​android​:layout_height=​"wrap_content" 
           ​android​:layout_weight=​"2" 
           ​android​:text=​"뒤로" ​/> 
 
       <Button 
           ​android​:id=​"@+id/forward" 
           ​android​:layout_width=​"0dp" 
           ​android​:layout_height=​"wrap_content" 
           ​android​:layout_weight=​"3" 
           ​android​:onClick=​"goForward" 
           ​android​:text=​"앞으로" ​/> 
   </LinearLayout> 
   
   <WebView 
       ​android​:id=​"@+id/webview" 
       ​android​:layout_width=​"match_parent" 
       ​android​:layout_height=​"match_parent" 
       ​android​:layout_below=​"@id/​upper​" ​/> 
 
</RelativeLayout> 
 
 
[MainActivity.java] 
package ​kr.mindwing.webbrowser​; 
 
import ​android.os.Bundle​; 
import ​android.support.v7.app.AppCompatActivity​; 
import ​android.view.KeyEvent​; 
import ​android.view.View​; 
import ​android.webkit.WebView​; 
import ​android.webkit.WebViewClient​; 
import ​android.widget.Button​; 
import ​android.widget.EditText​; 
import ​android.widget.Toast​; 
 
public class ​MainActivity ​extends ​AppCompatActivity { 
 
   ​private ​EditText textUrl​; 
   private ​WebView webView​; 
   private ​Button backButton​, ​forwardButton​; 
   private ​View.OnKeyListener listener = ​new ​View.OnKeyListener() { 
 
       @Override 
       ​public boolean ​onKey(View v​, int ​keyCode​, ​KeyEvent event) { 
           ​if ​(event.getAction() != KeyEvent.ACTION_DOWN) { 
               ​return false; 
           ​} 
 
           ​boolean ​processed = ​false; 
 
           switch ​(keyCode) { 
               ​case ​KeyEvent.KEYCODE_ENTER: 
                   webView.loadUrl(textUrl.getText().toString())​; 
 
                   ​processed = ​true; 
                   break; 
 
               default​: 
                   ​break; 
           ​} 
 
           ​return ​processed​; 
       ​} 
   }​; 
 
   ​@Override 
   ​protected void ​onCreate(Bundle savedInstanceState) { 
       ​super​.onCreate(savedInstanceState)​; 
       ​setContentView(R.layout.activity_main)​; 
       ​setupUI()​; 
   ​} 
 
   ​private void ​setupUI​() { 
       ​backButton ​= (Button) findViewById(R.id.​back​)​; 
       ​backButton​.setOnClickListener(​new ​View.OnClickListener() { 
 
           ​@Override 
           ​public void ​onClick​(View v) { 
               ​if ​(​webView​.canGoBack()) { 
                   ​webView​.goBack()​; 
               ​} ​else ​{ 
                   Toast.makeText(MainActivity.​this, ​"맨 뒷페이지 입니다."​, 
Toast.​LENGTH_SHORT​).show()​; 
               ​} 
           } 
       })​; 
 
       ​forwardButton ​= (Button) findViewById(R.id.​forward​)​; 
 
       ​textUrl ​= (EditText) findViewById(R.id.​text_url​)​; 
       ​textUrl​.setOnKeyListener(​listener​)​; 
       ​textUrl​.setText(​"http://google.com"​)​; 
 
       ​webView ​= (WebView) findViewById(R.id.​webview​)​; 
       ​webView​.setWebViewClient(​new ​WebViewClient())​; 
   ​} 
 
   ​public void ​goForward(View ​view​) { 
       ​if ​(webView.canGoForward()) { 
           webView.goForward()​; 
       ​} ​else ​{ 
           Toast.makeText(MainActivity.​this, ​"맨 앞페이지 입니다."​, 
Toast.LENGTH_SHORT) 
                   .show()​; 
       ​} 
   } 
} 
 
 
○ 뒤로 가기 버튼은 ​setOnClickListener()​ 메서드를 이용해서 OnClickListener 
객체를 통해 이벤트 핸들링을 합니다. 
○ 반면, 앞으로 가기 버튼은 xml 에서 ​onClick​ 속성을 이용해서 이벤트 핸들링에 
사용할 메서드를 지정합니다. 
■ 인자로 전달되는 View 객체는 앞으로 가기 버튼입니다. 
■ Button forwardButton = (Button) view; 
○ 이제 실행을 하면 다음 화면과 같은 모양이 됩니다. 
■ 더 이상 앞으로 갈 수 없거나 뒤로 갈 수 없을 때에는 안내 Toast 가 
뜹니다. 
 
 
 
 
○ 버튼을 보면 WebView 영역과 별다른 구분선이 없습니다. 
■ 이럴 때에는 <shape> 태그를 이용해서 구분을 지어주고 싶은 UI 
컴포넌트들에게 UI효과를 주면 됩니다. 
○ 다음과 같이 shape.xml 파일을 만들어주세요. 
 
 
 
 
 
 
○ shape.xml 파일이 만들어졌으면 다음 내용을 코딩해주세요. 
 
[res/drawable/shape.xml] 
<?​xml version=​"1.0" ​encoding=​"utf­8"​?> 
<shape ​xmlns:​android​=​"http://schemas.android.com/apk/res/android"​> 
 
   <solid ​android​:color=​"#ffffaf" ​/> 
 
   <stroke 
       ​android​:width=​"2px" 
       ​android​:color=​"#ff7f00" ​/> 
 
   <corners ​android​:radius=​"10dp" ​/> 
 
</shape> 
 
 
○ 다음과 같이 LinearLayout 에 shape 속성을 부여합니다. 
 
[activity_main.xml] 
... 
 
<LinearLayout 
   ​android​:id=​"@+id/upper" 
   ​android​:layout_width=​"match_parent" 
   ​android​:layout_height=​"wrap_content" 
   ​android​:background=​"@drawable/shape" 
   ​android​:orientation=​"horizontal" 
   ​android​:padding=​"1dp"​> 
 
... 
 
 
○ 이제 URL 입력창과 버튼들을 담는 Linear Layout 영역이 별도의 UI 효과를 
가지는 것을 볼 수 있습니다. 
 
 
 
○ Enter 키를 누르면 google.com 에 바로 접속해서 검색결과를 보거나 여러 
페이지간에 뒤로 가기와 앞으로 가기를 할 수 있습니다. 
 
 
 
 
 
   
○ 7) Design Support Library 를 이용하여 Snackbar 
써보기 
○ Android 는 API level 에 따라 추가기능을 제공하고 있습니다. 
■ LolliPop (API 21, 22) 보다 Marshmallow (API 23) 가 더 많은 기능을 
제공합니다. 
■ 따라서, API 23 에서 추가된 기능은 API 21 만 제공하는 안드로이드 
단말에서는 제공되지 않습니다. 
■ 단말제조사가 Marshmallow 업그레이드 서비스를 제공해주어야 
추가기능을 써볼 수 있습니다. 
○ 이러한 불편함을 해소하기 위해 API level 이 낮더라도 기존 기능만을 이용하여 
새로운 기능을 추가 구현하고, 이를 라이브러리형태로 배포해줍니다. 이런 
추가라이브러리를 support library 라고 합니다. 
■ 라이브러리 이름은 다음과 같이 생겼습니다. 
● com.android.support:appcompat­v7 
● com.android.support:design 
■ v7 이라고 버전숫자가 붙은 라이브러리는 최소한 API level 7 이상의 
단말이면 쓸 수 있다는 뜻입니다. 
■ 버전숫자가 없는 라이브러리는 특별히 제한되는 API level 은 없지만, 
Design Support Library 는 com.android.support:appcompat­v7 
라이브러리에 의존적이기 때문에 결론적으로 최소한 API level 7 
이어야 합니다. 
○ 이 강의에서도 이미 AppCompat Support Library 를 사용하고 있는데, Main 
Activity 가 상속하고 있는 AppCompatActivity 가 바로 그것입니다. 
■ 전체 이름은 android.support.v7.app.AppCompatActivity 입니다. 
 
 
import ​android.support.v7.app.AppCompatActivity​; 
 
..... 
 
public class ​MainActivity ​extends ​AppCompatActivity​ { 
 
 
○ 이렇게 Support Library 를 사용하고자 한다면 다음과 같이 build.gradle 파일에 
내용이 추가되어야 합니다. 
■ 빌드시스템에게 어떤 라이브러리를 쓸 것인지 알려주는 것입니다. 
 
 
[Gradle Scripts/build.gradle (Module: app)] 
apply ​plugin​: ​'com.android.application' 
 
android { 
   compileSdkVersion ​'Google Apis:Google Apis:23' 
   ​buildToolsVersion ​"23.0.2" 
 
   ​defaultConfig { 
       ​applicationId ​"kr.mindwing.webbrowser" 
       ​minSdkVersion ​15 
       ​targetSdkVersion ​23 
       ​versionCode ​1 
       ​versionName ​"1.0" 
   ​} 
   buildTypes { 
       release { 
           ​minifyEnabled ​false 
           ​proguardFiles ​getDefaultProguardFile​(​'proguard­android.txt'​), 
'proguard­rules.pro' 
       ​} 
   } 
} 
 
dependencies { 
   compile fileTree(​dir​: ​'libs'​, ​include​: [​'*.jar'​]) 
   testCompile ​'junit:junit:4.12' 
   ​compile ​'com.android.support:appcompat­v7:23.+' 
   ​compile ​'com.android.support:design:23.+' 
} 
 
 
○ 이 강의에서 추가로 쓰고자 하는 Support Library 는 design 입니다. 
○ 여기에서 제공하는 기능중 Snackbar 를 쓸 것입니다. 
■ Snackbar 는 Toast 와 유사한 기능을 제공하지만, Toast 는 앱의 
화면과 상관없이 그 위에 토스트처럼 툭~ 튀어나오는 기능이라면, 
Snackbar 의 경우 특정 View 를 기준으로 숨겨진 화면처럼 존재하며 
필요할 때마다 살짝 튀어나와서 내용을 보여줍니다. 
○ 다음과 같이 MainActivity 에서 Toast 를 띄우는 부분에 Snackbar 도 같이 
띄워보도록 코딩합니다. 
 
[MainActivity.java] 
package ​kr.mindwing.webbrowser​; 
 
import ​android.os.Bundle​; 
import ​android.support.design.widget.Snackbar​; 
import ​android.support.v7.app.AppCompatActivity​; 
import ​android.view.KeyEvent​; 
import ​android.view.View​; 
import ​android.webkit.WebView​; 
import ​android.webkit.WebViewClient​; 
import ​android.widget.Button​; 
import ​android.widget.EditText​; 
import ​android.widget.Toast​; 
 
public class ​MainActivity ​extends ​AppCompatActivity { 
 
   ​private ​EditText ​textUrl​; 
   private ​WebView ​webView​; 
   private ​Button ​backButton​, ​forwardButton​; 
   private ​View.OnKeyListener ​listener ​= ​new ​View.OnKeyListener() { 
 
       ​@Override 
       ​public boolean ​onKey​(View v​, int ​keyCode​, ​KeyEvent event) { 
           ​if ​(event.getAction() != KeyEvent.​ACTION_DOWN​) { 
               ​return false; 
           ​} 
 
           ​boolean ​processed = ​false; 
 
           switch ​(keyCode) { 
               ​case ​KeyEvent.​KEYCODE_ENTER​: 
                   ​webView​.loadUrl(​textUrl​.getText().toString())​; 
 
                   ​processed = ​true; 
                   break; 
 
               default​: 
                   ​break; 
           ​} 
 
           ​return ​processed​; 
       ​} 
   }​; 
 
   ​@Override 
   ​protected void ​onCreate​(Bundle savedInstanceState) { 
       ​super​.onCreate(savedInstanceState)​; 
       ​setContentView(R.layout.​activity_main​)​; 
       ​setupUI()​; 
   ​} 
 
   ​private void ​setupUI​() { 
       ​backButton ​= (Button) findViewById(R.id.​back​)​; 
       ​backButton​.setOnClickListener(​new ​View.OnClickListener() { 
 
           ​@Override 
           ​public void ​onClick​(View v) { 
               ​if ​(​webView​.canGoBack()) { 
                   ​webView​.goBack()​; 
               ​} ​else ​{ 
                   noti(​"맨 뒷페이지 입니다."​)​; 
               ​} 
           } 
       })​; 
 
       ​forwardButton ​= (Button) findViewById(R.id.​forward​)​; 
 
       ​textUrl ​= (EditText) findViewById(R.id.​text_url​)​; 
       ​textUrl​.setOnKeyListener(​listener​)​; 
       ​textUrl​.setText(​"http://google.com"​)​; 
 
       ​webView ​= (WebView) findViewById(R.id.​webview​)​; 
       ​webView​.setWebViewClient(​new ​WebViewClient())​; 
   ​} 
 
   ​public void ​goForward​(View view) { 
       ​if ​(​webView​.canGoForward()) { 
           ​webView​.goForward()​; 
       ​} ​else ​{ 
           noti(​"맨 앞페이지 입니다."​)​; 
       ​} 
   } 
 
   ​private void ​noti​(String str) { 
       Toast.​makeText​(​this, ​str​, ​Toast.​LENGTH_SHORT​).show()​; 
       ​Snackbar.​make​(​webView​, ​str​, ​Snackbar.​LENGTH_SHORT​).show()​; 
   ​} 
} 
 
○ noti() 메서드가 추가되었습니다. 
■ 이 메서드는 기존에 Toast 를 띄우던 코드를 대체해서 호출하도록 되어 
있으며, 이 메서드 안에서는 Toast 도 띄우고 Snackbar 도 띄웁니다. 
■ 두 개의 UI 가 어떻게 다른지 비교해보세요. 
 
 
   
○ 8) github 에서 프로젝트를 clone 하기 
○ 지금 작성된 코드는 다음 URL 에서 볼 수 있습니다. 
■ https://github.com/mindwing/Camp_WebBrowser 
○ Android Studio 에서 바로 clone 해서 빌드 후 안드로이드폰에 올려볼 수 
있습니다. 
○ Android Studio 2.0 을 쓰지 않는다면 clone 이후 에러가 발생할 수 있습니다. 
문제가 발생하신 분은 제가 직접 빌드환경을 수정해드리겠습니다. 
 
 
 
 
수고하셨습니다~ 
 
복습 꼭 하시고요. 
내용 분석해보시다가 궁금하신 
내용은 언제든지 Slack 에 
질문올려주세요. 
 

More Related Content

Similar to [Live coding 1-23 토] camp-web_browser

청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기Chris Ohk
 
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료오픈소스 컨트리뷰톤 2020 backend.ai 발표자료
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료지원 정
 
초보 개발자/학생들을 위한 오픈소스 트랜드
초보 개발자/학생들을 위한 오픈소스 트랜드 초보 개발자/학생들을 위한 오픈소스 트랜드
초보 개발자/학생들을 위한 오픈소스 트랜드 YoungSu Son
 
develop android app using intellij
develop android app using intellijdevelop android app using intellij
develop android app using intellijSewon Ann
 
개발자의 첫단계
개발자의 첫단계개발자의 첫단계
개발자의 첫단계yejiHong7
 
Python on Android
Python on AndroidPython on Android
Python on Android용 최
 
공간정보아카데미 - Day1 오픈소스개발 일반
공간정보아카데미 - Day1 오픈소스개발 일반공간정보아카데미 - Day1 오픈소스개발 일반
공간정보아카데미 - Day1 오픈소스개발 일반BJ Jang
 
Open source engineering - 0.1
Open source engineering - 0.1Open source engineering - 0.1
Open source engineering - 0.1YoungSu Son
 
GDG DevFest Busan 16" Android Nougat Developer's Note
GDG DevFest Busan 16" Android Nougat Developer's NoteGDG DevFest Busan 16" Android Nougat Developer's Note
GDG DevFest Busan 16" Android Nougat Developer's NoteSeok-yong Kim
 
모바일 해커톤 사전교육 1일차
모바일 해커톤 사전교육 1일차모바일 해커톤 사전교육 1일차
모바일 해커톤 사전교육 1일차Han Sung Kim
 
PyQGIS와 PyQt를 이용한 QGIS 기능 확장
PyQGIS와 PyQt를 이용한 QGIS 기능 확장PyQGIS와 PyQt를 이용한 QGIS 기능 확장
PyQGIS와 PyQt를 이용한 QGIS 기능 확장MinPa Lee
 
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for AppspressoKTH, 케이티하이텔
 
Android발표자료 홍종진
Android발표자료 홍종진Android발표자료 홍종진
Android발표자료 홍종진Jong Jin Hong
 
Cloud ide를 이용한_모바일_개발의_가능성과_전망
Cloud ide를 이용한_모바일_개발의_가능성과_전망Cloud ide를 이용한_모바일_개발의_가능성과_전망
Cloud ide를 이용한_모바일_개발의_가능성과_전망Sung-tae Ryu
 
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈Changhwan Yi
 
Hybrid App Platform - HyWAI 3.5
Hybrid App Platform - HyWAI 3.5Hybrid App Platform - HyWAI 3.5
Hybrid App Platform - HyWAI 3.5Jonathan Jeon
 
Open source engineering
Open source engineeringOpen source engineering
Open source engineeringYoungSu Son
 

Similar to [Live coding 1-23 토] camp-web_browser (20)

청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기
 
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료오픈소스 컨트리뷰톤 2020 backend.ai 발표자료
오픈소스 컨트리뷰톤 2020 backend.ai 발표자료
 
초보 개발자/학생들을 위한 오픈소스 트랜드
초보 개발자/학생들을 위한 오픈소스 트랜드 초보 개발자/학생들을 위한 오픈소스 트랜드
초보 개발자/학생들을 위한 오픈소스 트랜드
 
develop android app using intellij
develop android app using intellijdevelop android app using intellij
develop android app using intellij
 
개발자의 첫단계
개발자의 첫단계개발자의 첫단계
개발자의 첫단계
 
Python on Android
Python on AndroidPython on Android
Python on Android
 
공간정보아카데미 - Day1 오픈소스개발 일반
공간정보아카데미 - Day1 오픈소스개발 일반공간정보아카데미 - Day1 오픈소스개발 일반
공간정보아카데미 - Day1 오픈소스개발 일반
 
Open source engineering - 0.1
Open source engineering - 0.1Open source engineering - 0.1
Open source engineering - 0.1
 
GDG DevFest Busan 16" Android Nougat Developer's Note
GDG DevFest Busan 16" Android Nougat Developer's NoteGDG DevFest Busan 16" Android Nougat Developer's Note
GDG DevFest Busan 16" Android Nougat Developer's Note
 
Jung jaeyeoup
Jung jaeyeoupJung jaeyeoup
Jung jaeyeoup
 
모바일 해커톤 사전교육 1일차
모바일 해커톤 사전교육 1일차모바일 해커톤 사전교육 1일차
모바일 해커톤 사전교육 1일차
 
PyQGIS와 PyQt를 이용한 QGIS 기능 확장
PyQGIS와 PyQt를 이용한 QGIS 기능 확장PyQGIS와 PyQt를 이용한 QGIS 기능 확장
PyQGIS와 PyQt를 이용한 QGIS 기능 확장
 
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso[H3 2012] Bridge over troubled water : make plug-in for Appspresso
[H3 2012] Bridge over troubled water : make plug-in for Appspresso
 
Android발표자료 홍종진
Android발표자료 홍종진Android발표자료 홍종진
Android발표자료 홍종진
 
Portfolio
PortfolioPortfolio
Portfolio
 
Cloud ide를 이용한_모바일_개발의_가능성과_전망
Cloud ide를 이용한_모바일_개발의_가능성과_전망Cloud ide를 이용한_모바일_개발의_가능성과_전망
Cloud ide를 이용한_모바일_개발의_가능성과_전망
 
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈
2013 W3C HTML5 Day Conferences:HTML5 Game App 개발 및 이슈
 
Hybrid App Platform - HyWAI 3.5
Hybrid App Platform - HyWAI 3.5Hybrid App Platform - HyWAI 3.5
Hybrid App Platform - HyWAI 3.5
 
Anatomy of an android
Anatomy of an androidAnatomy of an android
Anatomy of an android
 
Open source engineering
Open source engineeringOpen source engineering
Open source engineering
 

[Live coding 1-23 토] camp-web_browser