늘모자란, 개발

늘모자란, 개발


삼성 덱스에서 앱을 시동하면, 모바일 기기 기준으로 실행된다.
그런데 아시다시피 DEX의 화면은 엄청나게 광활한데 앱 화면은 작디 작고 늘어나지도 않는다. 조금 더 크게 사용하고 싶을 수도 있다는 것이다.

이때 사용하는것이 Nougat 에서 추가된 멀티 윈도우 기능이다. 나보다 더 자세히 쓰여있는 삼성의 가이드 링크를 첨부하지만 그거도 눌러보기 싫은 사람들을 위해서 쓰자면

Manifest의 Application 부분에 다음을 추가한다.

android:resizeableActivity="true"


이때 구글의 문서를 보면 오타가 기재되있기도 한데, resiz e able 이다. resiz a ble 아니다. e를 뺴먹지 말자.
그리고 gradle의 complile sdk 옵션을 24 이상으로 설정해야한다. Nougat에서 추가된 기능이기 때문이다.
초기 실행되는 레이아웃 사이즈도 조절할 수 있어 보이는데, 그거까지 바라는 사람은 없을거같다. 여튼, 다원화시대니까,,,,

2018/08/31 13:18 2018/08/31 13:18
이번에 아이폰 아이폰X가 이슈가 되어서, 대응을 하기 위해 찾아보아서 정리겸 쓴다. 사실 어이없을떄 더 많이 쓰는 느낌이지만

아이폰 X가 노치 디자인을  채택함으로서, 아이폰에는 기존에 없던 새로운 개념이 생겨났다.
바로 이런 글들이다

iPhone X용 앱 업데이트하기 - iOS - Apple Developer - (Korean)

Human Interface Guidelines (iPhone X)

그런데 이건 노치 디자인을 얼마나 건드릴지에 관한 문제이고, 스토리보드를 쓰지 않는 앱에선 가이드라인 설정이 매우 어렵고, 그렇다고 스토리보드로 넘어가자니 또 작업량이 너무 많을것 같았다. 나는 그냥, 런치 이미지를 세팅해서 화면을 가득 채우고 싶을 뿐인데 왜 이런글을 읽는지도 모르겠고.  가이드라인을 쓰고 빌드해보려니 최소 iOS 버전을 올리라고 하고. 여간 번거로운게 아니었다.

다들 알겠지만, 런치 이미지는 image.xcassets 에서 아이콘과 함께 관리된다. 그런데 이 고민의 문제는 여기에 아이폰 X가 없었기 때문에 삽질을 시작했던건데, 그런 고민을 하고 있는 분이라면 당장 하고 있던거나, 검색창을 멈추길 바란다.

그냥, New를 해서 새로운 런치 이미지 보드를 만들면 가장 상위에 아이폰X가 있다 -_-
쓰던 런치 이미지들 그대로 옮겨서 다시 넣어주고, 아이폰X용 런치 이미지 넣어주면 아주 화면에 그득그득 꽉꽉 표시된다...
도대체 왜 이런지 알수가 없는데, 왜 기존 보드에 업데이트를 안해주고 new를 해야만 신규 기기에 대응할 수 있게 되는지 의문이다.
하여튼 새로운 런치 이미지 set을 만들고, 등록해주면 정상적으로 나온다. 오늘도 정말 하... 욕만 나온다.
2018/08/24 16:08 2018/08/24 16:08
어제, 오늘, 내일을 표현하는 말은 여러개가 있는 것 같다.
내일이나 어제라는 말 조차도 한자이지만, 굳이 격식을 차린다고 작일 명일 등으로 표기하는 경우가 있는 것 같은데, 이번에 오늘을 표현하는 말 중에 본일 이라는 말을 알게 되어서 기록 겸 남긴다.

어제 :: 작일, 전일 (예) 전일 보내드렸던 메일을 참고 부탁드립니다.
오늘 :: 금일, 본일 (예) 금일 방문하고자 합니다
내일 :: 명일, 익일 (예) 명일 처리 예정입니다.
특정일 :: 즉일, 당일 (예) 추석 당일에 시행될 예정이다.


2018/08/03 09:03 2018/08/03 09:03
지문인식 기능을 개발할 일이 있어서 개발을 완료했는데, 뒤늦게 다른 기기에서 동작을 안하는걸 발견했다.
분명히 테스트 기기 (Galaxy S6) 에서는 잘됐었는데, Pixel 및 Galaxy S8+ 에서는 동작을 하지 않는게 의아했다.
정확히는, 아예 안되는건 아니고 앱전환 화면으로 들어간다던지 해서 액티비티가 pause 후 resume 되면 멀쩡하게 동작하는걸 발견해서,
결국 로그를 찍어보게 되었는데 다음과 같은 에러가 발생하고 있었다

5, 지문 인식 작업이 취소되었습니다.


5가 뭔지 찾아보니까 FINGERPRINT_ERROR_CANCELED 로 정의되어 있었다.
단순히 FingerprintManager를 호출했을뿐인데 에러가 발생해서, onError 때문에 지문인증을 할 수 없게 되지만, 이상하게 resume 되면 매니저가 정상 동작하는게 좀 어이가 없기도 하고..

그래서 검색을 좀 해봤는데 이 글을 발견할 수 있었다.
@Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        if ( errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
            stopListening();
            restartListeningToFingerprint();
        }
}


코드는 별 달리 읽을것도 없고, 에러메세지 5번이 발생할 경우 Listening 을 멈추고 재시작하라고 되어있다.
즉 Android 구현상에 문제가 있다는건데... 왜 내 Galaxy S6 에서는 문제가 없었을까? 하니 링크된 구글 이슈트래커에서 내용을 발견할 수 있었다

This issue is not reproducible on all devices. The Samsung Galaxy S6 doesn't return this error whereas the Pixel XL emulator does.


그냥 적혀있는 댓글이라 100% 이렇다! 할 수는 없지만 일단 나같은 사람이 더 있다는거에 위안을 삼고..
이제 본격적으로 고쳐보자. 별로 고칠 내용도 없다.

상기 예문의 코드에서는 에러가 발생시 재시작 하라고 되어 있는데 정확히는 CancellationSignal 를 건드려야 한다.
CryptoObject를 저장해놨다가 다시 Listening 을 시작하고 하는 식으로 구현해봤으나 별 효과가 없고, 그냥 이 글에 나와 있는것 처럼 다음과 같이 작성하는게 직빵이다

@Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        if ( errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
            return;
        }
}
2018/07/17 09:22 2018/07/17 09:22
이크립스 프로젝트를 이제야(-_-) 안드로이드 스튜디오로 마이그레이션하게 되었는데 에러가 지속적으로 발생했다.
이것저것 들여다보고 있는 와중에 gradle 에 새로 도입한 aapt2 가 문제가 되고 있단걸 알게 되었다.

해결법은 간단한데, 그냥 비활성해버리면 되는것이다. 하지만 이건 프로젝트를 돌리는데 급급한거기때문에.. 결국 다 고쳐야된다.

gradle.properties

파일에 내용을 수정한다. 없으면 루트 디렉토리 최상단에 만든다

android.enableAapt2=false


작성!
2018/06/27 16:50 2018/06/27 16:50
docker에 mysql을 올려서 사용하고 있는데, 어느 순간 갑자기 어디서도 안붙어진다. 
localhost를 바라보고 있는 서비스 소스 측에선 사용이 되는데 도저히 외부에선 붙어지지가 않았다.

별도의 테스트 디비가 없기때문에 접속이 안되서 로컬호스트로 처리도 못하는 상황. 
mysql로 붙는 속도가 현저히 느려져서 skip-name-resolve 옵션을 켜기도 했는데..

권한이고 iptables고 ufw 고 확인안해본게 없는데 지푸라기라도 잡는 심정으로 docker를 재시작했더니 그냥된다.
그냥 docker-proxy가 얌전히 맛이가서 dns조회쪽에 문제가 됐던게 아닌가한다. 저 옵션은 사실 켜야될 필요가 없는데...
간만에 황당한거 겪어서 기록으로 남긴다.
2018/04/23 02:42 2018/04/23 02:42
제목을 지을땐 항상 희한한 기분이다.
문법이 맞나 싶어가지고.. 어쨌든 백업할때 느꼈던건데, 나는 docker를 그냥 디스크만 옮기면될줄알고 다른디스크에 똑같은 경로로 옮겼다.
그리고 docker_opt를 다시 잡아준 후에 docker start 를 통해 컨테이너를 실행하려니 정말 죽어도 안되는것이다.
별수를 다 써봤는데도 안되었다.

정말 이상한 일이라 검색해봤는데 나같은 사례가 없었다.
하긴 누가 디스크 to 디스크로 옮기는일을 할까.. 여튼 해답은 다음과 같다.

/docker/containerd/daemon/


해당경로에는 현재 돌아가고 있는 컨테이너의 정보들이 존재한다.
여기를 깔끔하게 지워주면 돌아가게 되는데 문제는 바로 여기

io.containerd.metadata.v1.bolt/meta.db


이 파일이다. 이 db파일내에 컨테이너 이름이 들어가있으면 docker는 해당 컨테이너가 이미 running 중이라고 판단한다.
즉, docker를 정상적으로 exit 한 상황이 아닌 상태에서 그냥 파일을 옮기면 meta.db엔 running 중인 상태로 기록되어 있기때문에 절대 돌릴 수가 없다.

해결법은 그냥 docker를 다시 깔고, 깔끔한 meta.db를 덮어쓰면된다. (데몬내에 다른 폴더들은 그냥 정리)
2018/03/15 15:51 2018/03/15 15:51
docker... 이 애증의 물건..

써본 사람은 알겠지만, docker와 스토리지 용량은 뗄 수 없는 관계이다.
항상 용량 문제에 항상 부딪히게 되는데 이건 소프트적으로 해결할 수 있는 용량이 아니다. 결국 물리적인 하드를 추가할 수 밖에 없었다...

이걸 왜 하게 됐냐면 이 글 의 내용 때문이다.
마지막으로, 서버 이미지를 하루마다 저장해 허브에 푸시합니다. DB 두개가 한번에 박살나도, 최대 10분내에 복구가 가능합니다.(순수하게 다운로드 시간)
라고 적어놨는데 허브에 푸시한다는건 말이 안된다. 일단 푸시 시간이 너무 어마무시하게 걸린다.
지금 내 이미지의 용량은 115기가쯤인데 48시간동안 docker push 했으나 결국 업로드에 실패했다... 컴퓨터가 먼저 리셋되었다.
결국 새 스토리지도 달았겠다 로컬에 저장해놓고 관리하기로 했다.

우선 현재 나는 2개 컨테이너를 운영중인데, MySQL 을 repl 화 해서 master / slave 로 나누어 관리하고 있다.
master와 slave의 차이는 my.cnf 와 같은 설정차이일뿐, 실 서비스 중인 master 컨테이너를 건드릴 필요는 없다.
그래서 slave를 commit 해서 새로운 이미지를 만들면된다. commit 중엔 컨테이너가 pause 상태에 빠지게 되는데, resume 되면 알아서 slave가 master로부터 데이터를 긁어와 동기화 되므로 별 걱정할 필요가 없다.

내 스토리지가 보관할 수 있는 이미지 갯수는 약 4개.
커밋 전 용량이 부족할 수 있으니 오래된 이미지를 정리한다. 이때 필터옵션을 줘서 오래된 이미지를 삭제 할 수 있다.

docker image prune -a -f --filter "until=3h"


이때, 필터옵션을 주지 않으면 사용하지 않는 모든 컨테이너가 삭제되므로 반드시 주의해야한다.
배치 작업을 위해 -f를 준거지 단순 정리목적이라면 -f를 사용하지 말고 !!반드시!! 재 확인이 필요함

그 이후, 컨테이너를 커밋한다.

docker container commit <CONTAINER> <IMAGE NAME:TAG>


인데 일반적으로 알고 있는 docker commit은 이미지에 commit 하는거고, 이건 container 를 기반으로 새로운 이미지를 만드는 것이다.
나같은 경우엔 TAG에 배치 시작 시간을 넣어줬는데, 태그는 아무래도 상관없다. creation date 로 prune 되기때문에 뭘 넣어도 상관없다.

이 과정에서 알게 된게 있는데,
같은 이름의 이미지명과 태그를 입력해 commit 하게 되면 commit 이 안되는게 아니고, 이름과 태그 둘다 none 으로 입력된다.

이렇게 해서 특정 시간마다 배치작업을 설정하게 되면, 3시간이 지난 이미지는 알아서 날아가고, 시간마다 새로운 이미지가 생성된다.
압축까지 해서 보관하는 방법도 있는데, 나는 그렇게까진 안하고.. latest 4시간만 보관하기로 했다.
2018/03/13 10:24 2018/03/13 10:24
https://www.acmicpc.net/problem/10797

이 쉬운걸 도대체 왜? 라고 생각할 수 있겠는데 내가 너무 어이가 없어서 남긴다.

문제는 간단하다. 그냥 list 에 있는 엘리멘트중에 원하는것을 세는 문제다. 그래서 처음엔 이렇게 만들었다.

 
target = int(input())
numbers = str(raw_input()).split(" ")
cnt = 0
for i in numbers:
    if int(i) == target: cnt = cnt + 1
print cnt


근데 런타임에러가 발생했다.
그래서 여기서부터 온갖 뻘짓을 다하기 시작했는데

나중에는

 target = str(raw_input())
numbers = str(raw_input()).split(" ")
cnt = 0
for i in numbers:
    if ord(i) == ord(target):
        cnt = cnt + 1
print cnt


str로 아스키코드로 비교하는거까지 만들었다. 근데 안된다. 

결론을 말하자면 for 안에서 i를 캐스팅하려고 하면 에러가 난다. 그래서 내부에 k라는 변수를 만들어 할당하고 캐스팅을 해봤는데도 에러가 나서 그냥 다음과 같이 처리했다

 target = str(input())
numbers = str(raw_input()).split(" ")
array = []
for i in numbers:
    array.append(i)
print array.count(target)


count는 안쓰고 싶었는데 안되니 별수가 없다. str 채로넣고 str로 비교해서 카운트해서 패스했다...
2018/02/01 16:25 2018/02/01 16:25
문서를 열때 "open as"를 누르면 복사할 앱을 선택하고 그 앱을 누르면 문서가 복사되며 파일이 열리는 구조란건 다들 알 것이다.
그런데 어느순간부터 이상한게, 파일명에 마침표(.)가 들어가면 열리질 않는것이다. 쉐어UI 조차 뜨지 않는다. 너무 이상하게 생각해서 여러테스트를 해봤는데,

한글만 문제인줄 알았더니 영어 파일 모두 문제가 되고 있다. 그냥 .이 두개 들어가면 확장자로 인식하지 않아 determine 할 수가 없다.
한마디로 그냥 쉣이다..

다들 그냥 이 OS는 원래 그런가보다... 하고 넘어가는 모양이다. 아니면 파일명을 따로 인코딩하고 있다던지.. 근데 기본 메일앱을 쓰는 사용자들은 그게 안되니까 ㅡㅡ

애플에 버그리포트를 했다. 결과는 어떻게 될지 모르겠다. 글 내용이 수정될일이 있을지..
2018/01/31 14:53 2018/01/31 14:53