[Android] 서비스 (Service)

참고링크 : https://developer.android.com/guide/components/services?hl=ko


서비스는 백그라운드에서 오래 실행되는 작업을 수행할 수 있는 애플리케이션 구성요소.

사용자 인터페이스 제공안함.


서비스는 본질적으로 두 가지 형식을 취함

  • 시작됨 : startService()를 호출하여 시작되며, 한번 시작되고 나면 백그라운드에서 무기한으로 실행 될 수 있음. 해당 서비스를 시작한 구성 요소가 소멸되었더라도 무관함. 작업을 수행하고 결과를 호출자에게 반환하지 않음
  • 바인드 됨 : bindService()를 호출하여 바인드 되며, 클라이언트-서버 인터페이스를 제공하여 구성 요소가 서비스와 상호작용할 수 있도록 해줌. 바인드된 서비스는 또 다른 애플리케이션 구성 요소가 이를 바인드되어 있는 경우에만 실행됨. 여러 개의 구성 요소가 서비스에 한꺼번에 바인드될 수 있지만, 이 모든 것이 바인딩을 해제하면 서비스가 소멸됨.

서비스는 위 두 가지 방식 모두 취할 수 있음.

서비스는 자신의 호스팅 프로세스의 기본 스레드에서 실행됨.

자신의 스레드를 직접 생성하지 않으며, 별도의 프로세스에서 실행되지도 않음.

기본 스레드 외부에서 작업을 수행해야 하지만, 사용자가 애플리케이션과 상호작용 중인 동안에만 수행하면 되는 경우라면, 서비스가 아니라 그 대신 새 스레드를 생성해야 함.


  • onStartCommand() : 다른 구성요소가 서비스를 시작하도록 요청한 경우.(바인딩만 제공시 이 메서드는 구현하지 않아도 됨.)
  • onBind() : 다른 구성요소가 서비스에 바인드되고자 하는 경우. 클라이언트가 서비스와 통신을 주고받기 위해 사용할 인터페이스를 제공해야 함. IBinder를 반환함.


한 구성 요소가 startService()를 호출하여 서비스를 시작하면(onStartCommand() 호출 발생) 해당 서비스는 스스로 stopSelf()나 다른 구성요소가 stopService()를 호출하기 전까지 실행 중인 상태 유지함.


한 구성 요소가 bindService()를 호출하여 서비스를 시작하면(onStartCommand() 호출 안함) 해당 서비스는 해당 구성 요소가 바인딩된 경우에만 실행됨. 모든 클라이언트로 바인딩 해제되면 소멸됨.


서비스는 기본적으로 메인 스레드에서 실행되므로, 성능에 영향일 미치는 작업은 서비스 내에서 새 스레드를 시작해야 함.


IntentService는 Service의 서브클래스로 기본 작업자 스레드를 생성하여 모든 시작 요청을 처리하되 한번에 하나씩 처리함. 여러 개의 요청을 동시에 처리하지 않아도 되는 경우 최선의 옵션. onHandleIntent()를 구현하면 됨. 시작 요청이 모두 처리된 후 서비스를 중단하므로 stopSelf()를 호출할 필요 없음.


onStartCommand() 메서드의 반환 값

  • START_NOT_STICKY : 서비스 중단되면 재생성 안됨.
  • START_STICKY : 서비스 중단되면 재생성하고 onStartCommand() 호출됨. null 인텐트로 처리됨.
  • START_REDELIVER_INTENT : 서비스 중단되면 재생성하고 onStartCommand() 호출됨. 서비스에 마지막에 전달된 인텐트로 처리됨.


바인드된 서비스를 생성하려면 onBind() 콜백 메서드를 구현하여 서비스와 통신을 위한 인터페이스를 정의하는 IBinder를 반환하도록 해야 함.


바인드된 서비스는 onStartCommand()를 통해 시작된 서비스와 달리 중단시키지 않아도 됨.


여러 클라이언트가 서비스에 한꺼번에 바인딩 된 경우 서비스와 상호작용 완료시 unbindService()를 호출하여 바인딩 해제함. 바인딩된 클라이언트가 없을 경우 서비스는 소멸됨.


포그라운드 서비스 실행시 startForeground()를 호출하며 상태 표시줄에 대한 알림인 Notification과 매개변수로 알림을 식별하는 정수를 사용함.(정수는 0이면 안됨.)

  • Unbounded Service
    • Call to startService()
    • onCreate()
    • onStartCommand()
    • Service running
    • The Service is stopped by itself or a client
    • onDestroy()
    • Service shut down
  • Bounded Service
    • Call to bindService()
    • onCreate()
    • onBind()
    • Clients are bound to service
    • All clients unbind by calling unbindService()
    • onUnbind()
    • onDestroy()
    • Service shut down


우려하던 대로 2019.01.02일자로 또 바뀌었네요. 내용 추가합니다.




앱에서 최신 앱 버전을 체크하기 위해 구글플레이의 링크를 이용해 따시는 경우들이 종종 있습니다. 


서버가 있어 서버에 등록하고 쓴다면 좋겠지만, 앱 업데이트시 마다 변경해야 하고 서버 자체가 없는 경우도 있다보니..


편의상 아래 링크처럼 구글플레이의 앱 링크를 열어 html을 긁어서 사용하는 모양새들인데요.


http://gun0912.tistory.com/8


언제인지는 정확히 모르겠지만... 기존에 알던 html 양식이 바뀌었습니다...;;;; (아마 2018.12월말부터??)


위 블로그에서는 2가지 방식을 권하고 있지요. jsoup을 사용하는 방식과 HttpURLConnection을 사용하는 법이요.


 먼저 jsoup을 사용하는 경우 기존 아래 같은 부분이..


	Elements Version = doc.select(".content");

	for (Element mElement : Version) {
		if (mElement.attr("itemprop").equals("softwareVersion")) {
			return mElement.text().trim();
		}
	}


아래와 같이 바꾸시면 되고요.


	Elements Version = doc.select(".htlgb").eq(3);

	for (Element mElement : Version) {
		return mElement.text().trim();
	}


HttpURLConnection을 사용하는 방식으로 하셨을 경우는 아래의 부분을..

	String startToken = "softwareVersion\">";
	String endToken = "<";


아래와 같이 바꾸시면 됩니다. (2018.04.17 일자 내용 추가)


	String startToken = "<div class="BgcNfc">Current Version</div><span class="htlgb"><div><span class="htlgb">";
        // 2018.04.17일자 이전
	// String startToken = "<div class=\"BgcNfc\">Current Version</div><div><span class=\"htlgb\">";
	String endToken = "</span></div>";


또 바겼습니다. 아래와 같이 바꾸시면 됩니다. (2019.01.04 일자 내용 추가)


	String startToken = "<div class=\"BgcNfc\">Current Version</div><span class=\"htlgb\"><div class=\"IQ1z0d\"><span class=\"htlgb\">";
// 2019.01.04일자 이전 // String startToken = "<div class="BgcNfc">Current Version</div><span class="htlgb"><div><span class="htlgb">"; // 2018.04.17일자 이전 // String startToken = "<div class=\"BgcNfc\">Current Version</div><div><span class=\"htlgb\">"; String endToken = "</span></div>";

다만 위와 같은 방법은 구글플레이 html 양식이 바뀐다면 또 문제가 되겠지요.


가능하시다면 번거럽더라도 다른 방법을 찾는게 맞을듯 싶습니다.


아 추가로 기존에 HttpURLConnection의 메소드 타입을 GET, POST 상관없이 구글플레이 html을 받아올 수 있었는데요.


오늘 확인해보니 POST로 할 경우 html을 받아올 수 없더군요. GET으로 하셔야 합니다.


이상 구글플레이에서 앱 버전 따기 간단히 남겨봅니다.

모든 프로그래밍 언어를 공부하기 시작할때 겪는 어려움들이 여러가지 있습니다.


그 중 개인적으로 제일 어려운 것이 프로그래밍 언어를 실제 사용해보기 위한 환경설정이었습니다.


하지만 요즘 핫한 언어들은 다양하고 쉬우면서 초보자들이 따라하기 좋은 튜토리얼 환경을 지원하는 경우들이 많은 것 같습니다.


예를 들어 코틀린이라던지 Kotlin이라던지 등등요. (사실 별로 아는게 없습니다;;)


https://try.kotlinlang.org/




무언가 직관적인 위 URL을 따라가보세요.


가셔서 Kotlin 문법을 사용해보시면 됩니다.


Kotlin Konas online 이라는 것으로 단계별 튜토리얼을 작성하며, 실제 코드가 제대로 작성되는지 체크도 가능하게 지원이 됩니다.


저도 아직 문서나 깨작거리며 보는 중이라 Konas는 진행을 못해보았지만요. 


문서보다 직접 코드를 만지며 배우고자 하시는 분들에게 큰 도움이 될 것 같네요.


일단 저는 문서에 나오는 코드를 깨작거려보고자 위 링크로 들어가 아래와 같이 코드를 넣어봅니다.



fun main(args: Array) {
    val a: Int = 1
    val b = 2
    val c: Int
    c = 3
    println("a = $a, b = $b, c = $c")
}


자 이제 첫 Kotlin 코드도 넣어봤으니, 우측 상단에 Run 버튼을 눌러봅니다.



어라, 무언가 이상하네요. 무언가 알 수 없는 에러가 발생합니다. 


아래 Problems View 를 확인하니 Error 문구가 쓰여있네요. 더블클릭해 해당 위치를 확인합니다.


Test.kt의 TestStart 라는 저도 모르는 아이에서 에러가 발생했네요.


보아하니 원래 Task.kt의 start()라는 함수를 호출하려다 제가 Task.kt의 코드를 함수명채로 바꾸다 보니 에러가 발생한 것이네요.


그러고 보니 좌측 메뉴에 보이는 Kotlin Konas라는 애들은 주제마다 Task.kt와 Test.kt로 구성이 되어 있네요.


아마 주제마다 UnitTest 형식으로 사용자의 결과물을 호출하여 값까지 체크하려고 하는 것 같습니다.


그렇다면 주제와 무관한 코드를 확인하고자 했을때엔 Test.kt도 수정해야되는 불편함이 생길 것 같네요. 이건 아닌것 같습니다.


하여 좌측 메뉴에 Kotlin Konas 위 Examples를 눌러봅니다.


이 아이를 누르니 또 다양한 주제들이 리스트로 나오고 있네요.


그 중에서 Hello, world! 그리고 Simplest version 항목을 선택해 봅니다.


역시 이곳에 확인하고자 하는 코드를 넣어봅니다.


그리고 마찬가지로 우측 상단의 Run 버튼을 눌러봅니다.


아 이제야 아래 Console 창을 통해 제가 원하는 결과를 확인할 수가 있네요.


앞으로 간단한 Kotlin 코드들은 이렇게 확인해 볼 수 있을 것 같네요.


원래 안드로이드에 대한 되새김질을 어느정도한 후에 코틀린을 시작하려 했었는데요.


어떤 계기에 의해 막연하게라도 코틀린을 접해봐야겠다는 생각이 들었습니다.


코틀린 쪽 문서들을 훑어보면서 겉핥기식 스터디를 시작하려 합니다.


당분간 아래 링크를 자주 쓰게 될 것 같네요. ㅋ


https://try.kotlinlang.org



내년부터 Google Play Console에 앱을 등록/업데이트시 최신 API를 지정하는 것을 필수 사항이 된다고 합니다.


  • 2018년 8월 : 새로운 앱은 Target API 26 (Android 8.0) 이상.
  • 2018년 11월 : 기존 앱 업데이트시 Target API 26 이상.
  • 2019년 이후 : 매년 targetSdkVersion 올라감. 


이와 더불어 2019년 8월부터 새 앱 등록시 64비트 코드로 등록이 가능하다고 합니다.

(64비트 관련 JNI 미사용시 호환에 크게 문제가 없다고 함. 링크 )


관련 링크들 참조 : 







  

내가 보려 정리해보는 도서 목차


핵심만 골라 배우는 안드로이드 스튜디오 3 & 프로그래밍 (닐 스미스/심재철) - Jpub


목차



CHAPTER 1 개요 _ 1


 

CHAPTER 2 안드로이드 스튜디오 개발 환경 구성하기 _ 6


 

CHAPTER 3 안드로이드 스튜디오로 첫 번째 애플리케이션 만들기 _ 28


 

CHAPTER 4 안드로이드 스튜디오 UI 둘러보기 _ 46


 

CHAPTER 5 안드로이드 스튜디오에서 AVD 생성하기 _ 58


 

CHAPTER 6 안드로이드 스튜디오 AVD 에뮬레이터 사용과 구성하기 _ 75


 

CHAPTER 7 실제 안드로이드 장치에서 애플리케이션 테스트하기 _ 86


 

CHAPTER 8 안드로이드 스튜디오 코드 편집기 _ 98


 

CHAPTER 9 안드로이드 아키텍처 개요 _ 111


 

CHAPTER 10 액티비티와 인텐트 개요 _ 117


 

CHAPTER 11 안드로이드 애플리케이션과 액티비티 생명주기 _ 122


 

CHAPTER 12 액티비티 상태 변화 처리하기 _ 128


 

CHAPTER 13 액티비티 상태 변화 예제 _ 138


 

CHAPTER 14 액티비티 상태를 저장하고 복원하기 _ 150


 

CHAPTER 15 안드로이드 뷰, 뷰 그룹, 레이아웃 _ 158


 

CHAPTER 16 안드로이드 스튜디오 레이아웃 편집기 살펴보기 _ 164


 

CHAPTER 17 안드로이드 ConstraintLayout 개요 _ 177


 

CHAPTER 18 안드로이드 스튜디오에서 ConstraintLayout 사용하기 _ 185


 

CHAPTER 19 안드로이드 스튜디오에서 ConstraintLayout 체인과 비율 사용하기 _ 199


 

CHAPTER 20 ConstraintLayout 예제 프로젝트 _ 209


 

CHAPTER 21 직접 XML 레이아웃 작성하기 _ 224


 

CHAPTER 22 ConstraintSet으로 ConstraintLayout 관리하기 _ 230


 

CHAPTER 23 안드로이드 ConstraintSet 예제 프로젝트 _ 238


 

CHAPTER 24 안드로이드 이벤트 처리 개요 _ 247


 

CHAPTER 25 안드로이드 스튜디오의 Instant Run 사용하기 _ 257


 

CHAPTER 26 터치와 다중 터치 이벤트 처리하기 _ 263


 

CHAPTER 27 안드로이드 제스처 감지 클래스로 일반 제스처 처리하기 _ 272


 

CHAPTER 28 커스텀 제스처와 핀치 인식 구현하기 _ 280


 

CHAPTER 29 안드로이드 프래그먼트 개요 _ 295


 

CHAPTER 30 안드로이드 스튜디오에서 프래그먼트 사용하기 ― 예제 프로젝트 _ 305


 

CHAPTER 31 오버플로 메뉴 생성과 관리 _ 323


 

CHAPTER 32 안드로이드 전환 프레임워크 _ 335


 

CHAPTER 33 beginDelayedTransition을 사용한 안드로이드 전환 _ 348


 

CHAPTER 34 안드로이드 장면 전환 구현하기 _ 355


 

CHAPTER 35 플로팅 액션 버튼과 스낵바 사용하기 _ 365


 

CHAPTER 36 탭 인터페이스 생성하기 _ 379


 

CHAPTER 37 RecyclerView와 CardView 사용하기 _ 393


 

CHAPTER 38 RecyclerView와 CardView 예제 프로젝트 _ 399


 

CHAPTER 39 앱 바와 컬랩싱 툴바 레이아웃 사용하기 _ 411


 

CHAPTER 40 내비게이션 드로어 구현하기 _ 421


 

CHAPTER 41 안드로이드 스튜디오 마스터/디테일 플로 _ 430


 

CHAPTER 42 안드로이드 인텐트 개요 _ 444


 

CHAPTER 43 명시적 인텐트 예제 프로젝트 _ 451


 

CHAPTER 44 암시적 인텐트 예제 프로젝트 _ 463


 

CHAPTER 45 브로드캐스트 인텐트와 브로드캐스트 수신자 _ 474


 

CHAPTER 46 스레드와 스레드 핸들러 _ 488


 

CHAPTER 47 스타트 서비스와 바운드 서비스 개요 _ 499


 

CHAPTER 48 스타트 서비스 구현 예제 프로젝트 _ 506


 

CHAPTER 49 로컬 바운드 서비스 예제 프로젝트 _ 518


 

CHAPTER 50 원격 바운드 서비스 예제 프로젝트 _ 529


 

CHAPTER 51 안드로이드 7의 알림 개요 _ 537


 

CHAPTER 52 안드로이드 7 알림의 직접 응답 구현 _ 550


 

CHAPTER 53 안드로이드 스튜디오에서 Firebase 사용하기 _ 559


 

CHAPTER 54 Firebase 원격 알림 사용하기 _ 567


 

CHAPTER 55 안드로이드 7의 다중 창 지원 개요 _ 575


 

CHAPTER 56 다중 창 예제 프로젝트 _ 585


 

CHAPTER 57 안드로이드 SQLite 데이터베이스 개요 _ 593


 

CHAPTER 58 TableLayout과 TableRow 개요 _ 603


 

CHAPTER 59 안드로이드 SQLite 데이터베이스 예제 프로젝트 _ 611


 

CHAPTER 60 콘텐트 제공자 이해하기 _ 622


 

CHAPTER 61 콘텐트 제공자 구현하기 _ 627


 

CHAPTER 62 구글 클라우드 스토리지 액세스하기 _ 643


 

CHAPTER 63 안드로이드 스토리지 액세스 프레임워크 예제 프로젝트 _ 652


 

CHAPTER 64 비디오 재생 구현하기 _ 666


 

CHAPTER 65 카메라 인텐트를 사용한 비디오 녹화와 이미지 캡처 _ 675


 

CHAPTER 66 런타임 퍼미션 요청하기 _ 683


 

CHAPTER 67 안드로이드 오디오 녹음과 재생하기 _ 693


 

CHAPTER 68 구글 맵 API 사용하기 _ 707


 

CHAPTER 69 안드로이드 인쇄 프레임워크 사용하기 _ 727


 

CHAPTER 70 HTML과 웹 콘텐트 인쇄 예제 프로젝트 _ 738


 

CHAPTER 71 안드로이드 커스텀 문서 인쇄 _ 750


 

CHAPTER 72 안드로이드 지문 인증 구현하기 _ 768


 

CHAPTER 73 서로 다른 안드로이드 장치와 화면 처리하기 _ 787


 

CHAPTER 74 안드로이드 애플리케이션 릴리스하기 _ 793


 

CHAPTER 75 구글 플레이 인앱 결제를 애플리케이션에 통합하기 _ 804


 

CHAPTER 76 안드로이드 스튜디오의 그래들 개요 _ 829


 

CHAPTER 77 안드로이드 스튜디오 그래들 빌드 예제 프로젝트 _ 841


 

찾아보기 _ 853 
 ※ 부록 A, B는 독자들의 이해를 위해 옮긴이가 작성한 특별 부록입니다. 
아래의 사이트에서 예제 프로젝트 파일과 함께 무료로 다운로드받으실 수 있습니다.

 

APPENDIX A 코틀린 핵심 파악하기: 개요와 실습 환경 구축


 

APPENDIX B 코틀린 핵심 파악하기: 구성 요소와 문법


 



'Android개발' 카테고리의 다른 글

[Android] DataBinding Library 3  (0) 2018.06.12
[Android] DataBinding Library 2  (0) 2018.06.12
[Android] DataBinding Library 1  (2) 2018.06.12
[Android] 프로세스(process) 및 스레드(thread)  (0) 2018.06.08
[Android] 서비스 (Service)  (0) 2018.06.08

Android 앱 개발을 하면서 서버와 통신을 위해 네트워크 기능을 쓸 경우가 대다수이다.


기존 네트워크 기능을 위해 HttpURLConnectionHttpClient (OS 6.0 부터 삭제) 등이 쓰여왔고, OS 3.0 (API 11) 이후에 


NetworkOnMainThreadException 를 피하고자 Thread, AsyncTask 등을 사용하기도 했다.


그 후 여러 편의성을 제공하는 통신 라이브러리 들이 등작하였다. OkHttp, Volley (설명), Retrofit ... (라이브러리 비교)


그 중에서 최근까지 많이 쓰이고 있는 Retrofit에 대해서 초간단 맛만 보기로 하자.


0. 준비물 : API, Android Studio, 잠시나마 집중하겠다는 마음가짐.


1. API

직접 준비하기 어려울 경우 공개되어 있는 고마운 API들을 찾아서 사용해보자. 

예를 들면 빗썸 OPEN API 같은... 


연습을 위해 https://api.bithumb.com/public/ticker/{currency}를 사용해보자.


2. build.gradle 설정

dependencies에 retrofit 최신버전을 추가한다. (Gson 사용을 위해 Gson 관련 추가한다.)


dependencies {
    compile 'com.google.code.gson:gson:2.8.2'                 // Gson 사용시
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'     // Gson 처리시
    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'  // String 처리시
    ...
}


3. Data 클래스 

결과 JSON에 맞춰 Data 클래스를 생성하자. (Json to Java Object 서비스)


public class BithumbTickerData {
    @SerializedName("opening_price")
    public String openingPrice;
    @SerializedName("closing_price")
    public String closingPrice;
    @SerializedName("min_price")
    public String minPrice;
    @SerializedName("max_price")
    public String maxPrice;
    @SerializedName("average_price")
    public String averagePrice;
    @SerializedName("units_traded")
    public String unitsTraded;
    @SerializedName("volume_1day")
    public String volume1day;
    @SerializedName("volume_7day")
    public String volume7day;
    @SerializedName("buy_price")
    public String buyPrice;
    @SerializedName("sell_price")
    public String sellPrice;
    @SerializedName("date")
    public long date;
}

public class BithumbTicker {
    @SerializedName("status")
    public String status;
    @SerializedName("data")
    public BithumbTickerData data;
}


4. interface 생성

API Method 방식 및 Path에 대해서 정의하자.


    public interface OpenApiService {
        @GET("public/ticker/{path}")
        Call tickerInfo(@Path("path") String path);
    }


5.1. Retrofit 초기화

Retrofit 생성 후 사용할 interface를 통해 서비스를 만들자. (Response를 String 형태로 받고 싶다면 ScalarsConverterFactory 사용)


        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.bithumb.com/")
                .addConverterFactory(GsonConverterFactory.create())        // Gson 처리시
                //.addConverterFactory(ScalarsConverterFactory.create())  // String 등 처리시
                .build();
        OpenApiService openApiService = retrofit.create(OpenApiService.class);


5.2. Call 생성

만들어 둔 interface를 호출하는 Call을 생성하자.


        Call tickerInfo = openApiService.tickerInfo("BTC");


5.3. Callback 정의

enqueue() 를 통해 Callback에 대해서 정의하자.


        tickerInfo.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                Toast.makeText(TestMainActivity.this, response.body().toString(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                Toast.makeText(TestMainActivity.this, t.toString(), Toast.LENGTH_SHORT).show();
            }
        });


이상으로 간단하게 Retrofit 시식을 마칠까 한다.




Retrofit 로그 보는 법과 Proguard 설정에 대해서 추가한다.


6. 로그 보는 법

build.gradle에 아래와 같이 추가한다.


dependencies {
        compile 'com.squareup.okhttp3:logging-interceptor:3.9.1'
        ...
}


그리고 Retrofit 초기화 하는 부분에 아래와 같이 추가한다.


        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        Retrofit.Builder retrofitBuilder = new Retrofit.Builder().baseUrl(url);

        if(BuildConfig.DEBUG) {
            retrofitBuilder.client(client);
        }

        if(!isString) {
            retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
        } else {
            retrofitBuilder.addConverterFactory(ScalarsConverterFactory.create());
        }
        Retrofit retrofit = retrofitBuilder.build();


기존과 비교했을 때 OkhttpClient 라는 놈을 Retrofit Builder에 추가하는 모습이 보인다.

개인적으로 디버그 모드일때만 로그를 보기 위해 BuildConfig.DEBUG 로 분기 처리를 하였다.

그리고 로그 수준은 아래와 같다.


public final class HttpLoggingInterceptor implements Interceptor {
   ...
  public enum Level {
    /** No logs. */
    NONE,
    /**
     * Logs request and response lines.
     *
     * 

Example: *

{@code
     * --> POST /greeting http/1.1 (3-byte body)
     *
     * <-- 200 OK (22ms, 6-byte body)
     * }
*/ BASIC, /** * Logs request and response lines and their respective headers. * *

Example: *

{@code
     * --> POST /greeting http/1.1
     * Host: example.com
     * Content-Type: plain/text
     * Content-Length: 3
     * --> END POST
     *
     * <-- 200 OK (22ms)
     * Content-Type: plain/text
     * Content-Length: 6
     * <-- END HTTP
     * }
*/ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). * *

Example: *

{@code
     * --> POST /greeting http/1.1
     * Host: example.com
     * Content-Type: plain/text
     * Content-Length: 3
     *
     * Hi?
     * --> END POST
     *
     * <-- 200 OK (22ms)
     * Content-Type: plain/text
     * Content-Length: 6
     *
     * Hello!
     * <-- END HTTP
     * }
*/ BODY }

위 소스를 보면 로그 레벨은 NONE, BASIC, HEADERS, BODY 로 이루어져 있다. 필요에 따라 설정하면 된다.

- NONE : No logs.

- BASIC : Logs request and response lines.

- HEADERS : Logs request and response lines and their respective headers.

- BODY : Logs request and response lines and their respective headers and bodies (if present).


위와 같이 하였을 때 로그는 아래와 같이 떨어진다.


12-26 17:53:03.411 15500-15624/com.test.testblabla D/OkHttp: --> GET https://api.bithumb.com/public/ticker/BTC
12-26 17:53:03.411 15500-15624/com.test.testblabla D/OkHttp: --> END GET
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: <-- 200 https://api.bithumb.com/public/ticker/BTC (693ms)
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: date: Tue, 26 Dec 2017 08:53:04 GMT
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: content-type: application/json
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: set-cookie: __cfduid=dd24fcf80c27cf456c60e275644e40a0e1514278384; expires=Wed, 26-Dec-18 08:53:04 GMT; path=/; domain=.bithumb.com; HttpOnly
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-origin: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-methods: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-headers: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: set-cookie: ci_session=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22cf7e414ece7af81b8a35a0cdcaccd317%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A12%3A%221.227.62.114%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A12%3A%22okhttp%2F3.9.1%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1514278384%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D4ca3239efcb6f4f81c5c8703401ade3bbef4e9fd; expires=Tue, 26-Dec-2017 10:53:04 GMT; Max-Age=7200; path=/
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: server: cloudflare-nginx
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: cf-ray: 3d32cec0fef194b7-NRT
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: {"status":"0000","data":{"opening_price":"19157000","closing_price":"20632000","min_price":"18853000","max_price":"21400000","average_price":"19977707.8742","units_traded":"26050.76859352","volume_1day":"26050.76859352","volume_7day":"176662.05473862","buy_price":"20620000","sell_price":"20623000","date":"1514278384536"}}
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: <-- END HTTP (323-byte body)

참조링크1 : https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor

참조링크2 : https://stackoverflow.com/questions/32514410/logging-with-retrofit-2


7. Progaurd 설정

앱을 실제 signed release apk 만들시 Progaurd 사용하는데, 이때 Retrofit 사용시 아래와 같이 proguard.pro 파일에 추가해준다.


# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions


Retrofit 로그에서 문제가 될시 아래도 추가해 보자.


-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

참조링크1 : http://square.github.io/retrofit/

참조링크2 : https://github.com/square/okhttp

추가로 아래 이슈 발생시 대응에 대한 링크 추가합니다.

- shouldOverrideUrlLoading() 내 처리 및 loadUrl() 후 return true 시 WebView 히스토리 꼬임 현상 등


수정 : https://support.google.com/chrome/forum/AAAAP1KN0B0uMbcDTxbqA4/?hl=en



아래 이슈들이 지난 2017.12.15 자로 업데이트 된 Chrome 63.0.3239.111 버전에서는 해결된 것으로 보입니다.


63버전이지만 위 버전보다 아래일 경우는 아래 이슈 내용을 확인할 필요가 있을 듯 싶네요.


추가로 T멤버십, 원스토어 쪽의 Chrome 63버전 이슈에 대한 공지 링크 붙입니다.


T멤버십 : http://www.tworld.co.kr/normal.do?serviceId=S_ETC_0084&viewId=V_CMN_0076&seq=1712150001


원스토어 : https://dev.onestore.co.kr/devpoc/support/news/noticeView.omp?noticeId=30722




구글 플레이의 업데이트 날짜로 2017.12.13 자로 Chrome 63.x 버전이 업데이트 되었습니다.


점진적 업데이트인지 단말마다 업데이트 버전이 다른 상태입니다.


안드로이드 7.0 이상에서는 Chrome WebView를 사용하고 있었죠. (참조)


하나 63버전 Chrome WebView를 사용한 앱들에서 몇몇 이슈들이 발견되고 있습니다.


- Web 페이지 내의 iFrame 사용시 iFrame에서 Cookie 접근이 안되는 현상 (request header가 날라갔다는 이야기도 있습니다.)


- shouldOverrideUrlLoading() 내 처리 및 loadUrl() 후 return true 시 WebView 히스토리 꼬임 현상 등


관련 링크들.


https://bugs.chromium.org/p/chromium/issues/detail?id=793648


- https://chromium-review.googlesource.com/c/chromium/src/+/827018


https://www.facebook.com/groups/gdg.korea.android/permalink/2030069960555125/


당장 해결책은 설정->앱관리->크롬->사용중지(업데이트 제거) 하여 크롬을 초기버전으로 돌리는 수 밖에 없어 보입니다.


카드사 등을 시작으로 많은 결제 관련 서비스들이 문제가 되고 있으며, 이에 대해 고객에게 크롬 문제점을 가이드하고 있는 것으로 보입니다.


WebView를 사용하는 앱을 서비스하고 계시다면 유의하시기 바랍니다.

역동적인 UI 지원을 할 수 있는 Lottie 라이브러리(2017년 2월에 airbnb에서 출시)에 대해서 초간단히 알아보자.


Android Source 예제 : http://airbnb.io/lottie/android/android.html


Lottie Json 샘플 : https://www.lottiefiles.com/


Lottie는 안드로이드(ICS/API14부터), iOS, 리액트 네이티브, 웹까지 다양한 플랫폼을 지원한다.


다 알아본 것 같다. 이제 돌려보자.


0. 준비물 : Lottie Json 샘플, 잠시나마 집중하겠다는 마음가짐.


Lottie Json 샘플은 Lottie Files 에서 마음에 드는 것을 선택하도록 한다.


원래는 주로 디자이너들이 쓸 것으로 보이는 After Effect 의 출력물인 .aep 파일을 After Effect의 플러그인인 

BodyMovin 을 통해서 json 파일을 뽑아낼 수 있다고 한다. (참조)

하지만 After Effect가 뭔지도 모르는 입장인지라 Lottie Files 에서 샘플을 받아 진행하기로 한다.


1. 샘플 json 파일을 assets 폴더에 넣어준다.




1. build.gradle 에 dependencies에 lottie를 추가한다.

dependencies {
    compile 'com.airbnb.android:lottie:2.3.0'
    ...
}


2. 사용할 xml에 LottieAnimationView를 추가한다.  이 때 json 경로를 넣어도 된다.

    <com.airbnb.lottie.LottieAnimationView
        android:id="@ id/animation_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:lottie_fileName="penguin.json"
        app:lottie_loop="true"
        app:lottie_autoPlay="true" />


3. LottieAnimationView에 json 설정 후 동작시킨다. 이 때 Listener를 달아 Animation 이벤트 처리도 가능하다.

        LottieAnimationView animationView = (LottieAnimationView) findViewById(R.id.animation_view);
        animationView.setAnimation("rejection.json");
        animationView.loop(true);
        animationView.playAnimation();


생각보다 간단하게 Lottie 를 시식코너 마냥 맛만 볼 수 있었다.

앱 개발을 위해 안드로이드 OS 버전 대응이 필요한 시점들이 있다.


그를 위해 OS 버전별 차이점이 필요한 부분들도 있다.


검색하다 찾은 사이트이다. 


http://socialcompare.com/en/comparison/android-versions-comparison


비록 OS 버전별 사용자 차이점에 치중되어 개발 차이점이 없긴 하지만 아쉬운대로 참고할만 하다.


뒤져보면 이것저것 비교공유한 내용들이 있어 필요시 참고할만 하다.




OS 버전별 분포도도 추가한다.


출처 : https://developer.android.com/about/dashboards/index.html

VersionCodenameAPIDistribution
2.3.3 -
2.3.7
Gingerbread100.4%
4.0.3 -
4.0.4
Ice Cream Sandwich150.5%
4.1.xJelly Bean162.0%
4.2.x173.0%
4.3180.9%
4.4KitKat1913.4%
5.0Lollipop216.1%
5.12220.2%
6.0Marshmallow2329.7%
7.0Nougat2419.3%
7.1254.0%
8.0Oreo260.5%


위 도표는 Android Developer 사이트에서 퍼온 것으로 아래와 같은 내용이 본문에 있다.


"최신 Google Play 스토어 앱을 실행하고 Android 2.2 이상과 호환이 되는 기기를 반영합니다. 데이터의 각 스냅샷은 7일 전까지 Google Play 스토어를 방문한 모든 기기를 나타냅니다."


"2017년 12월 11일까지 7일 동안 수집된 데이터 배포율이 0.1% 이하인 버전은 표시되지 않습니다."


OS 버전 최근동향이 필요할시 참고하면 된다.

+ Recent posts