프로그래밍 354

[안드로이드] Google SafetyNet Attestation으로 기기 무결성을 확보하기 (클라이언트/서버 Python)

SafetyNet Attestation으로 기기 무결성을 확보하기 SafetyNet Attestation 구현을 위해서 클라이언트(앱)와 서버에서 필요한 절차들을 나누어 설명할 예정이다. 전체 절차 서버에 Nonce를 요청한다. 해당 요청에 대한 Nonce를 생성하여 다시 앱으로 돌려준다. 앱에서 해당 Nonce를 싣고 SafetyNet API를 호출하여 Google Services에 Attestation을 요청한다. Attestation 결과를 JWT로 받는다. 받은 결과를 서버로 전송한다. 서버는 JWT를 통해 Attestation 검증 후 결과를 앱으로 돌려준다. 클라이언트 API 키 얻기 SafetyNet Attestation API 호출을 위해 API 키를 먼저 얻어야한다. GCP에서 API 키..

[안드로이드] WebView 사용시 "Uncaught TypeError: Cannot read property 'getItem' of null" 해결

WebView에서 웹을 띄울때 어떤 경우에는 아래 콘솔메세지가 출력되면서 제대로 작동이 안되는 경우가 있다. 나는 네이버 한자사전(https://hanja.dict.naver.com/#/main)을 띄우다가 경험했다. Uncaught TypeError: Cannot read property 'getItem' of null 웹의 JS 쪽에서 localStorage.getItem() 이나 sessionStorage.getItem() 사용시 DOM Storage를 사용할 수 없어서 나타나는 오류인데, WebView Settings에서 DOM Storage를 사용할 수 있도록 설정해주면 해결된다. webView.getSettings().setDomStorageEnabled(true);

파티션 테이블로 Big Query 쿼리 비용 대폭 절감하는 법 (Partitioned table)

Big Query에서 쿼리를 날릴때 처리되는 용량을 가지고 요금이 매겨지는데, 그래서 "실행시 이 쿼리가 xxbyte 를 처리합니다" 라는 곳을 유심히 지켜봐야한다. Big Query에서는 테이블을 날짜별, 시간별, 또는 정수 기준으로 나눈 파티션을 나눈 테이블을 지원하는데, 이를 이용하면 처리되는 데이터의 양을 대폭 줄일 수 있다. 파티션 테이블을 사용하지 않았을때 다음은 으로 집어서 쿼리를 날렸을때 처리되는 데이터 양이다. SELECT event_timestamp, user_pseudo_id, param, user_id FROM `table-1605078626536.analytics_252952500.*`, UNNEST(event_params) as param WHERE event_name = 'fu..

프로그래밍/SQL 2021.05.28

[안드로이드] Kotlin에서 addOnGlobalLayoutListener 사용하기 (lambda에서 자신을 참조하는 법)

Kotlin Lambda에서 this 참조가 제대로 걸리지 않아서 (지원하지 않는다고 함) addOnGlobalLayoutListener를 일회성으로 사용하기가 어려웠다. 이렇게 적어서 구현하고 싶었지만...방황하는 this... view.viewTreeObserver.addOnGlobalLayoutListener { // TODO... view.viewTreeObserver.removeOnGlobalLayoutListener(this) } SelfReference를 추가하여 구현하면된다. class SelfReference(val initializer: SelfReference.() -> T) { val self: T by lazy { inner ?: throw IllegalStateException(..

[안드로이드] 루팅 기기 체크하는 법 (Rooted device detection)

루팅 여부 체크를 위해서 새로 개발하기 귀찮으니 Rootbeer를 사용하고 있었는데, 루팅이 되어있지 않은 기기에도 루팅되었다는 false positive 케이스가 나와서 다른 방법을 찾아보게되었다. 오류 리포팅을 위해 Sentry를 앱에서 사용하고 있었는데, Sentry에서 root 체크가 되길래 Sentry의 RootBeer와 RootChecker 클래스를 참고하여 만들었다. RootBeer의 간단한 버전이라고 보면 되겠다.

[블록체인] NFT 거래소에 내 그림을 파는 방법, NFT 만들기 (Opensea.io)

NFT 무슨 그림이 72억에 팔렸다더라...일론 머스크 부인이 20분만에 60억을 챙겼다더라하는 뉴스를 보면 NFT라는 말이 등장한다. NFT란 Non-Fungible Token, 대체 불가능한 토큰이다. Fungible Token의 하나인 비트코인을 예로 들자면 나의 1 BTC와 일론 머스크가 가진 1 BTC는 동등한 가치를 지닌다. 서로 교환해도 가치가 같으니까 되는거다. 반면, NFT는 내가 가진 토큰과 다른 사람이 가진 토큰의 가치가 상이해서 1:1 교환을 할 수가 없다. 똑같은 캔버스 사이즈에 그린 피카소의 그림과 고흐의 그림처럼 말이다. 모든 디지털 자원을 NFT로 만들 수 있고, NFT의 이러한 특성때문에 현재 거래소에는 그림, 움짤, 가상 세계의 땅 등이 활발하게 거래되고 있다. 흠! 다른..

[JD-GUI] 실행시 오류 해결방법 No suitable Java version found on your system!

No suitable Java version found on your system! This program requires Java 1.8+ Make sure you install the required Java version. BigSur에서 JD-GUI를 실행시켰더니 이런 오류가 뜨며 안될 경우 JD-GUI 아이콘 우클릭 > 패키지 내용 보기 > Contents/MacOS/universalJavaApplicationStub.sh에 다음 라인을 추가한 후 저장한다. 위치는 주석 끝나고 맨 처음으로! export JAVA_HOME=$(/usr/libexec/java_home -v11) 이제 JD-GUI를 켜면 제대로 작동된다.

[안드로이드] 색상 변화 애니메이션 만들기 (ValueAnimator / Color change animation)

Target API 21 이상으로 설정한다. private fun animateRainbow() { val anim = ValueAnimator.ofArgb( Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA ).apply { duration = 1000 * 5 repeatCount = ValueAnimator.INFINITE repeatMode = ValueAnimator.REVERSE addUpdateListener { // tvRainbow가 TextView이다. binding.tvRainbow.setBackgroundColor(it.animatedValue as Int) } } anim.start() }각 컬러 값들은 ContextC..

[안드로이드] 앱이 버벅거리지 않게 하기 위해서 해야할 일

앱이 버벅댄다는건, 60FPS가 나오지 않는 상태를 의미한다. 16ms마다 그리기를 완성해야하는데 작업량이 많아 그것보다 시간이 더 걸리게되면 사용자가 알아채기 시작한다. 버튼이 그려지기까지의 과정 버튼같은 UI 오브젝트들은 먼저 CPU에의해 폴리곤(Polygon)과 텍스쳐(Texture)로 변환되어야한다. 이 변환 작업도 시간이 많이 걸리며(time-consuming), 이들을 CPU에서 OpenGL ES API를 통해 GPU로 업로드하는 작업도 시간이 많이 걸린다. GPU는 이들을 픽셀로 바꾸어 스크린에 보일 수 있게 만든다. 이 작업을 래스터화(Rasterization)라고한다. GPU로 올라간 메쉬(mesh)는 곧바로 사라지지않고, GPU에 머물게되고 나중에 사용할 일이있을때 재사용하게 된다. 메..