소개


안드로이드 어플리케이션은 클래스 파일, 레이아웃, 문자열 데이터, 해상도 별 이미지 등 수많은 데이터 조합으로 이루어져 있었다. 하지만 안드로이드가 발전하면서 새롭게 등장하는 앱들의 평균 사이즈 또한 증가하면서 사용자들이 용량이 큰 앱은 설치하지 않거나 설치 후에도 용량 확보를 위해 금방 삭제하는 현상이 증가하고 있다고 발표했다.



용량이 큰 앱은 다운로드와 설치 시간이 길고 업데이트 설치 비율이 낮아진다.


기존 안드로이드 앱 설치 방식은 모든 데이터를 시스템에 복사한다. 해상도 별 이미지, 제공하는 모든 국가별 문자열 데이터 등 모두 같이 설치한다. 해상도를 변경하거나 시스템 언어를 변경하지 않은 이상 현재 사용하는 설정 이외의 모든 데이터를 쓸모가 없어진다. 즉 사용자는 쓰지도 않는 이미지나 문자열 데이터를 앱 때문에 가지고 있는 것이다. 


안드로이드 개발팀은 이러한 단점을 보완하고자 새로운 앱 모델을 선보였는데 바로 앱 번들이다. 앱 번들은 구글 플레이 서비스에서 시스템이 사용하는 설정 데이터(해상도나 언어)만을 조합하여 앱을 설치하는 형태로 진행된다. 필요한 데이터로만 구성된 앱을 설치하기 때문에 앱 크기를 줄일 수 있고 다운로드, 설치, 업데이트 시간을 단축할 수 있게 된다.



좌측은 기존의 방식으로 모든 데이터를 가져와 설치한다.

우측의 경우 앱 번들에서 시스템 해상도, 언어, 아키텍처의 데이터만 가져와 설치한다.


이로 인해 같은 앱이더라도 기존 방식에 비해 최대 35%까지 앱 크기를 줄일 수 있게 된다. 그런데 만약 앱을 사용하다가 중간에 시스템 언어를 바꾸거나 해상도를 변경할 경우 새로 설치해야 하나? 답은 아니다. 언어나 해상도나 변경될 경우 구글 플레이 서비스가 인식하여 알아서 필요한 파일을 다운로드한다. 때문에 시스템 설정이 변경되어도 재설치 없이 그대로 사용할 수 있게 된다.


앱 번들은 Split APK 방식으로 설치하기 때문에 구글 플레이 서비스에서 앱 번들에서 필요한 데이터만 조합한 뒤 재-서명 과정을 거치게 되는데 이를 위해 개발자 키가 개발자 콘솔에 등록되어야 한다. 다만 보안 문제는 걱정할 것이 없는 이유가 구글에서 개발자 키를 자신들이 사용하는 구글 키와 동일한 저장소에 보관한다고 하였기 때문이다.


구조 및 사용법


앱 번들은 안드로이드 스튜디오 3.2 이상부터 사용 가능하다. 앱 번들을 사용하기 위해 기존 개발 구조가 크게 바뀌거나 추가할 필요는 없다. 간단하게 APK로 서명하던 것을 Bundle 형태로 서명하면 된다. Bundle로 빌드 시 기존 APK 파일 형태가 아닌 AAB(Android App Bundle)로 배포되며 APK와 다른 구조를 가지게 된다.



출처

https://developers-kr.googleblog.com/2018/05/google-io-2018-whats-new-in-android.html

https://developer.android.com/guide/app-bundle/

https://www.youtube.com/watch?v=QdoEcfibGs&list=PLWz5rJ2EKKc8WFYCR9esqGGY0vOZm2l6e&index=15

by JamesY 2018. 11. 12. 23:36

소개


웹사이트에서 계정 또는 개인 정보 조회를 위해서는 본인 인증 과정을 거쳐야 한다.


공인인증서, 이메일, 핸드폰, 힌트 등 다양한 방식의 인증 방식이 존재하는데


이 중 핸드폰 인증은 본인 명의의 핸드폰으로 문자메세지를 전송해 메세지 내


존재하는 인증 번호를 화면에 입력하는 인증 과정을 거친다.


한두번이야 직접 입력할 수 있지만 일정 횟수를 넘어가면 짜증이 난다.


거의 그럴일도 없겠지만 간혹 반복해야 하는 경우가 생기는데 이로 인해 발생하는 짜증을


조금 덜어내고자 안드로이드 앱과 프로그램을 개발하였다.


소켓 기반으로 작성되었고 한 개의 서버는 한 개의 기기(스마트폰)만 연결 가능하다.


때문에 가장 먼저 연결하는 기기만 사용 가능하며 혹시 모를 외부 기기 접속을 방지하기 위해


간단한 인증도 가능하다. 또한 서버에서 직접 접속한 기기를 끊을 수도 있다.


Copy Pack.zip


위 압축 파일에는 윈도우 실행 프로그램과 안드로이드용 설치 파일이 있다.


아래는 소스 코드이며 Checksum도 존재하니 의심스러울 경우 확인 가능하다.


서버 프로그램 소스 코드 (Java)

https://github.com/Hot6ix/CopyServer


안드로이드 앱 소스 코드 (Kotlin + Java)

https://github.com/Hot6ix/CopyClient



주의 사항


  • 공공에서 제공하는 네트워크 접속 후 사용하는 것을 권장하지 않습니다.
  • 추가 설정 시 외부에서도 접속은 가능하지만 인증번호는 노출 시 위험한 정보이므로 같은 네트워크 안에서만 사용하는 것을 권장합니다.
  • 개발자는 프로그램 사용으로 인해 발생하는 피해를 책임지지 않습니다.


간단 사용 방법


서버 프로그램


실행 시



아이콘 오른쪽 클릭 시


가장 위쪽의 IP(192.168.1.23)를 기억해두자


IP는 컴퓨터마다 다르므로 직접 확인




클라이언트 프로그램


앱 실행 시 (권한 허가 필수)



IP 메뉴를 눌러 아까 기억해둔 IP를 입력



IP 입력 후 연결하기를 누르면 다음과 같이 연결되었다고 뜬다.




연결되었다고 뜰 경우 끝난다.


테스트로 자신한테 숫자를 포함한 메세지를 보내면 PC에 인증번호가 복사되었다고 메세지가 뜰 것이다.


메세지가 뜬 후 Ctrl + V 를 눌러 복사해보면 숫자가 복사된 것을 알 수 있다.



기타 설정


- 서버 프로그램


첫 실행 시 같은 폴더에 설정 파일인 setting.ini 파일을 생성한다.


설정 파일은 비밀번호, 포트, 문자 허용 여부를 수정할 수 있다.


비밀번호(password)의 기본 값은 빈칸으로 인증 과정을 거치지 않느다.


인증을 추가하려면 원하는 비밀번호를 입력하면 된다.


다만 비밀번호는 별도로 암호화되지 않고 또한 통신 과정에서도 plain text로 교환한다.


port는 앱과 서버가 통신하기 위한 통로로 특별한 경우가 아닌 경우 그대로 둘 것을 권장한다.


allowCharacter는 문자 허용 여부로 앱으로부터 받은 데이터 내 숫자아 아닌 문자가 포함되있을 경우


복사할지 말지 결정하는 값으로 false는 복사하지 않고 true 변경 시 복사한다.


설정 파일을 수정/저장 뒤 메뉴 중 서버 재시작을 누르거나 직접 프로그램을 재시작하면 적용된다.



- 클라이언트 앱


부팅 시 연결은 부팅 시 자동으로 서버와 연결할지 결정하는 옵션이다.


필터는 받은 문자메세지에서 인증번호를 추출하는 필터로 정규 표현식(Regex)를 사용하기 때문에


좀 더 정확한 필터링을 원할 경우 수정할 수 있다.


IP와 Port는 서버 프로그램을 실행 중인 기기와 맞춰주면 된다.


비밀번호의 경우 위의 설정 파일에서 비밀번호를 설정한 경우 입력해주면 된다.


by JamesY 2018. 10. 25. 17:17

Oreo 버전부터는 일반적인 Background 서비스를 사용하기 까다로워 졌다.


일단 서비스 실행 후 앱이 보이지 않거나 (액티비티가 화면에 나오지 않는 등) 


Foreground 서비스를 사용하지 않거나


IME, 배경화면 서비스, 알림 리스너, 음성 또는 텍스트 서비스 중 하나를 사용하지 않는 이상


서비스는 오래가지 않아 종료된다.


Foreground 서비스는 서비스 실행과 동시에 알림(Notification)을 보여주어 사용자가 서비스가 동작 중이라는 것을 인지시켜 주며 실행을 유지한다.


- Foreground 서비스를 실행

startService(Intent(context, Service::class.java))

- 서비스 내에서 Foreground 실행 함수를 호출해야한다.

startForeground(FOREGROUND_ID, notification)

이렇게 사용하면 서비스는 알림을 띄우며 동작하게 된다.


이후 서비스를 종료하기 위해서는 서비스 클래스 내에서 stopSelf() 함수를 호출하거나


외부에서 context.stopService(intent)를 호출하면 된다.


종료하는 과정에서는 알림 역시 제거된다. 하지만 알림을 제거하지 않고 서비스를 종료하기 위해서는 클래스에서 또는 클래스 내에서 onDestroy 함수에서 

stopForeground(Service.STOP_FOREGROUND_DETACH)

를 추가하면 된다.


주의해야할 사항은 위 함수는 Nougat(API 24)이상부터 사용가능하다.


또한 boolean값을 받는 같은 함수가 존재하는데 false를 주어도 서비스 종료 시 알림이 제거된다.

by JamesY 2018. 10. 23. 22:56

웹 개발에서 게시판을 만들면 일반적으로 Pagination도  구현해 문서를 일정 단위 개수로 페이지를 보여줘야 한다.


전체 글 수를 간단하게 10개씩 보여주는 건 간단하게 가능하다. 하지만 전체 글이 90개라면 페이지는 1 ~ 10이 아닌


1 ~ 9까지만 보여줘야 한다. 이러한 작업을 위해서는 데이터베이스의 10개 단위 글만 가져오는 것이 아니라 전체 글 수도 가져와야


페이지 끝을 정해 줄 수 있다. 보통은 리스트를 가져오는 쿼리와 전체 글 수를 가져오는 쿼리를 각각 돌려 작업한다.


이러한 방법이 아닌 한번에 가능한 방법을 찾다가 Aggregation 파이프라인 명령어 중 하나인 $facet를 알게 되었다.


https://docs.mongodb.com/manual/reference/operator/aggregation/facet/


간단하게 설명하면 $facet는 하나의 스테이지 안에서 여러 개의 파이프라인을 돌릴 수 있도록 해주는 파이프라인이다.


{ $facet:
   {
      <outputField1>: [ <stage1>, <stage2>, ... ],
      <outputField2>: [ <stage1>, <stage2>, ... ],
      ...

   }
}


작성법은 다음과 같다.


하나의 결과값을 나타내는 outputField는 반드시 대괄호로 묶어야 하며 중괄호나 소괄호 사용 시 오류가 발생한다.


이 파이프라인을 이용해서 전체 글 수와 글 10개를 가져올 수 있다.


{ $facet: {     'documents': [ {$skip: 10}, {$limit: 10} ],     'total': [ { $count: 'count' } ] } }


documents 필드는 전체 글 중 11번째 글부터 20번째 글을 가져온다.

total 필드는 전체 글 수를 가지는 count 필드를 가진다.


Compass를 통해 Aggregation을 실행하면 결과값은 다음과 같다.


  1. documents
    :
    Array
    1. 0
      :
      Object
    2. 1
      :
      Object
    3. 2
      :
      Object
    4. 3
      :
      Object
    5. 4
      :
      Object
    6. 5
      :
      Object
    7. 6
      :
      Object
    8. 7
      :
      Object
    9. 8
      :
      Object
    10. 9
      :
      Object
  2. total
    :
    Array
    1. 0
      :
      Object
      1. count
        :
        34188


document 필드 내 각 object는 하나의 글 데이터이다.


이렇게 두번의 쿼리를 사용하지 않고 한번에 전체 글 수와 일정 개수의 문서를 가져올 수 있다.


단순히 게시판 뿐만 아니라 여러 결과 값을 하나의 데이터로 만들고 싶을 때 $facet를 사용하면 된다.

'MongoDB' 카테고리의 다른 글

사용자 정의 날짜/시간 포맷을 ISOdate로 변환  (0) 2018.08.19
by JamesY 2018. 9. 10. 17:41

API로 데이터를 받았는데 timestamp나 일반적인 날짜/시간 포맷이 아닌 경우가 있다.


whois에서 제공하는 도메인 조회 api의 경우 날짜 포맷이 YYYY. mm. dd. 형태로 되어있다.


나중에 날짜/시간을 읽어 분석하는 서비스를 제공해야할 경우 Mongo DB가 아래와 같이 읽을 수 없어 곤란한 상황이 올 수 있다.




이러한 경우 Aggregate의 $dateFromString을 사용하여 사용자 포맷을 정해주면 읽어들일 수 있다.


https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/


{ $dateFromString: {
     dateString: <dateStringExpression>,
     format: <formatStringExpression>,
     timezone: <tzExpression>,
     onError: <onErrorExpression>,
     onNull: <onNullExpression>
} }


dateString : 변환할 날짜/시간 데이터 (필수)

format : 변환할 날짜/시간 포맷 (옵션)

timezone : 날짜/시간에 적용할 시간대 (옵션)

onError/onNull : 이벤트 발생 시 출력할 결과 (옵션)


여기서 예제는 앞서 말한 whois open api의 날짜 포맷인 YYYY. mm. dd. 로 한다.


db.dates.aggregate( [ { $project: { date: { $dateFromString: { dateString: '$date', format: '%Y. %m. %d.' } } } } ] )


$date는 날짜/시간 데이터를 가지고 있는 column명이다.

format은 api에서 제공하는 날짜/시간의 포맷을 넣었다.



위의 명령어를 mongo console에 적고 누르면 다음과 같이 결과가 출력된다.


성공적으로 변환되어 출력된 것을 볼 수 있다.


이제 위 명령어에 명령어를 덧붙여 collection에 적용되도록 한다.


적용을 하기 위해서는 $out을 사용한다.


https://docs.mongodb.com/master/reference/operator/aggregation/out/


*** $out의 collection은 위 명령어와 같은 collection을 쓸 경우 date를 제외한 모든 데이터 날라가므로 새로운 collection에 저장하도록 합시다. (테스트한다고 직접 겪어봄. 다 날림)


db.dates.aggregate( [ { $project: { date: { $dateFromString: { dateString: '$date', format: '%Y. %m. %d.' } } },

$out: { 'outputCollection' }

} ] )


이후 outputCollection을 확인해보면 console에서 확인한 결과값이 저장되어 있으므로 이후 update를 통해 데이터를 갱신하도록 한다.

by JamesY 2018. 8. 19. 01:40

Admob을 포함한 광고 플랫폼은 개발자에게 용돈을 주는 고마운(?) 존재이다. 


물론 앱에 광고를 너무 많이 넣진 않고 미관을 해치지 않는 선에서만 추가한다.


처음부터 Admob을 추가해 앱을 개발하는 것을 고려했기 때문에 개발 초기에는 앱 실행 시 속도 차이를 크게 못느꼈다.


그러나 업데이트를 하면서 이런저런 기능을 추가하게 되면서 Admob이 실행 속도에 영향을 주기 시작했다.


참고로 앱의 실행 방식은 3가지가 존재한다.

Cold start, Hot start, Warm start


자세한 정보는 아래 링크에 자세히 서술되어 있다.

https://developer.android.com/topic/performance/vitals/launch-time


여기서 실행 속도가 느리다는 것은 Cold start이다.


Cold start 속도가 3초 후반대에서 4초 대로 늘면서 원인을 찾아본 결과 Admob이었다.


이러한 문제를 해결하기 위해서 검색한 결과


1. https://stackoverflow.com/a/31636336


위 링크에서 제공하는 다양한 방법이 있다.


2. https://stackoverflow.com/a/19446364


위 링크는 1번 링크의 첫번째 링크의 내용이다.


Handler를 사용하여 광고를 불러오는 소스 코드를 1초 딜레이를 주고 실행한다.


정말 단순히 Handler를 추가했을 뿐인데 2초에서 3초 사이로 실행 시간을 줄일 수 있었다.


by JamesY 2018. 7. 27. 23:52

1. Adapter의 onBindViewHolder 함수에서 holder의 adapterposition 값을 저장하지 말 것

- Drag and drop 기능 구현 시 adapterposition을 저장한 값을 사용하면 이전 값을 가져오거나 잘못된 값을 가져올 수 있음


2. Adapter의 onBindViewHolder 함수에서 특정 이미지나 텍스트를 변경 시 조건문으로 만들 것

- 기본적으로 recyclerview는 아이템을 재사용하기 때문에 재사용된 데이터가 다른 위치에서 보일 수 있다. 하지만 정확히 조건문을 구현하여 변경 전과 후를 구현하면 방지할 수 있다.


3. Adapter 내 getItemCount 함수와 getItemId 함수를 구현할 것

- 2번과 비슷한 이유로 재사용 이슈로 인해 일부 잘못 표기되는 경우가 존재한다.


4. Listview의 head/foot view는 Recyclerview에선 view type으로 구현 가능

- Recyclerview는 listview와 별개로 별도의 head/foot view를 만들 수 있는 함수가 없다. 좀 더 확장한 개념의 view type을 사용하여 단순히 head/foot view 뿐만 아니라 리스트 데이터의 따라 다양한 형태로 view를 구현 가능하다.


5. Recyclerview에서 drag and drop 기능과 swipe 기능 구현

https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf


* 개발하면서 배우는 점을 지속적으로 업데이트할 예정

by JamesY 2018. 7. 22. 21:56

뷰잉(Viewing) 셋탑박스 리뷰


TV의 HDMI 포트 하나가 작동되지 않아 NAS의 영상을 재생하려면 일일이 노트북과 연결해야 했다.

NAS의 영상을 노트북 없이 바로 연결하기 위해 Chromecast, 미 박스 등 여러 스트리밍 기기를 찾고 있던 도중 지마켓에서 뷰잉 이벤트를 해서 뷰잉을 구매하게 되었다.



이틀 전 주문 후 오늘 수령



박스를 뜯자 뽁뽁이에 포장되었던 뷰잉 박스



뷰잉 박스를 열자마자 뷰잉 셋탑박스를 볼 수 있다.



구성품은 뷰잉 셋탑박스, HDMI 케이블, 충전 어댑터, 리모컨, 퀵 설치 가이드로 간단하게 구성되어 있다.




뷰잉 셋탑박스는 전원을 연결하자마자 바로 켜진다.

원래는 HDMI 케이블을 바로 TV에 연결하지만 TV HDMI 포트 하나가 동작하지 않으므로

HDMI 스위치에 연결



필요한 포트를 모두 연결 후 TV를 확인하면 리모컨과 페어링하라는 화면을 볼 수 있다.

페어링을 마치고 CJ ONE, 구글 등 여러 로그인 방법 중 하나를 선택하여 로그인한다.

안드로이드 스마트폰 사용 시 간단한 작업을 통해 스마트폰을 리모컨처럼 사용할 수도 있다.



모든 작업을 마친 후 로딩 중...



느리다는 댓글과 리뷰와 달리

생각보다 화면 전환도 빠르고 앱 실행도 빠릿하다.

안드로이드 TV OS라 구글 플레이 스토어도 이용 가능하다.

NAS 안 영상 재생을 위해 DS Video 앱과 MX Player도 설치


위의 사진은 Youtube를 실행하여 Battlefield 5 Trailer를 재생한 모습




실시간 TV도 지원한다. (모든 채널을 지원하는 것은 아님)

리모컨에는 Viewing, Pooq, Netflix, Tving 버튼이 각각 존재하여 필요 시 바로 실행할 수 있다.

다만 NAS 영상 중 일부는 버벅이는 경우도 발생하여 조금 아쉽기도 하다.


마무리


NAS 영상 시청 시 일일이 HDMI 케이블을 교체해야되는 귀찮음을 덜기 위해 구매하였지만

생각보다 괜찮은 성능을 보여주었고

VOD, 유튜브, 넷플릭스 등 다양한 앱도 지원하기 때문에 만족스러운 제품이다.



by JamesY 2018. 5. 30. 19:05

출처 : https://developer.android.com/training/basics/intents/filters.html?hl=ko


* Android studio를 사용하는 경우 Tools - App Links Assistant를 통해서도 생성이 가능하다.


-  AndroidManifest.xml에서 intent-filter를 등록

<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="https"
android:host="*" />
</intent-filter>


- App Links Assistant를 사용하면 테스트도 가능하다.

by JamesY 2018. 2. 13. 19:23

Google Maps Utility KML


적용 및 사용 방법 : https://developers.google.com/maps/documentation/android-api/utility/kml?hl=ko


1. 현재 공식 지원 중인 KML Utility는 베타 버전으로 일부 태그는 부분적으로 지원하거나 지원되지 않음


2. 1번의 이유로 Style 태그는 지원하지만 StyleMap 태그는 부분적으로 지원함 - 강조(Hightlight)는 지원안됨


3. KmlContainer는 하나의 Document 또는 Folder를 지칭함


4. 일반적으로 Style 관련 태그는 첫번째 Container에 포함되어 있음


5. Placemark의 style을 가져오기 위해서는 Style 태그가 포함된 Container에서 getStyle 함수를 통해 가져올 수 있음 


6. normal 상태와 highlight 상태를 가지는 StyleMap의 id는 불러오면 오류 발생


7. StyleMap id 뒤에 '-normal' 혹은 '-highlight'를 붙이면 getStyle 함수를 통해 데이터를 가져올 수 있음


8. layer에서 addLayerToMap 함수는 normal 상태의 style만 적용


9. addLayerToMap로 불러와도 색이 적용되지 않는 이유는 데이터에 내용이 누락됨 (이유는 알 수 없음)


* 이 외 style과 관련된 팁을 발견하면 추가 예정


* 이 팁들은 구글 내 지도 서비스에서 KML 내보내기를 통해 얻은 KML 파일을 기준으로 작성되었습니다.

by JamesY 2018. 1. 22. 19:38
| 1 2 3 |