늘모자란, 개발

늘모자란, 개발


Intent setResult 관리

Android 2019/08/02 15:57
금번에 앱을 수정하는데 intent 전환시 반환되는 requestCode가 무슨짓을 해도 0이 나와서 삽질을 했다
아무래도 기본적인 이해가 없이 땜질만하다보니 (주로 퍼온코드들을 넣다보니) 이런일이 발생하게 된것 같은데...

대상이 되는 액티비티는 A, B, C 세개였는데

처음에는 A가 B를 불러주고, B가 C를 부르는 구도인데
B에서 C를 무슨수를 써도 C에서 받는 RequestCode가 0이었다. 이게 왜그럴까 하면서 많은 삽질을 했는데...

좀 파보니 A가 B를 이렇게 부르고 있었다

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
...
startActivityForResult(intent, 0);


근데 이렇게 하면 A가 B를 부르고 다시 A에게 돌아간거나 다를바가 없었다.
호출되는 상황이 다르기때문에 B의 result를 그대로 써야하는데 이렇게 되면 0으로만 값이 반환되는것이었다

그래서 이런 상황에서는 B의 반환값을 그대로 사용하기 위해서 다음과 같이 써야한다.

A를 다음과 같이 고친다

intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
...
startActivity(intent);



B는 하던데로 setResult에 값을 적고 반환한다.

setResult(Value, intent);


A는 B와 C사이의 커뮤니케이션에 아무 상관이 없는 친구이므로, 관심꺼라고 명시를 해줘야 제대로 전달된다.
사실, 이 디자인은 문제가 좀 있었는데 B가 A를 상속받고, 핸들러로 처리하면 될 문제였으나... A를 상속하지 않은채로 만들어진 쌩짜의 액티비티라 이런일이 생길수도 있던것 같다...
2019/08/02 15:57 2019/08/02 15:57
TL;DR
apktool로 디컴파일-컴파일 했을때 망하면 다음을 확인해보자
classpath 'com.android.tools.build:gradle:3.1.4' -> 3.1.4 이상부터 뭘 해도 안된다.


자세히
내가 만든 앱을 디컴파일 및 컴파일 해야되는 계기가 생겼는데 (왜 이런 삽질을 하냐고 묻진 말자... 자본주의...)
갑자기 이런 에러가 나면서 재 컴파일이 되지 않았다.

Public symbol array/XXXXXX declared here is not defined.


이런게 막 수십줄이 뜨고 마지막에는 

brut.androidlib.AndrolibException 이 뜨면서 으마으마한것들이 잔뜩 나오며 실패했다.
minSDK 문제인지 targetSDK 문제인지 진짜 뭔 별 안해본게 없는데 커밋로그들을 쭉 둘러보면서 바뀐게 뭔가 하다가 설마 gradle 버전 문제인가 싶어서 기존에 쓰던 3.1.4로 낮춰서 빌드를 해 재컴파일 해보았더니 그냥 된다...

3.1.4에서 올린 이유는 이런 에러가 나왔기 때문인데
The rule `-keep public class *extends java.lang.annotation.Annotation {


gradle 버전을 올리니 더 뜨지 않아서 올렸던 기억이 있다. 그런데.. 이런 사태가 난 것이다.
좀 실험을 했는데 3.2.1 도 해보고, 3.3.1도 해봤는데 뭘 해도 안된다. 그냥 3.1.4만 된다. 혹은 그 아래버전도 되겠지만 그건 필요가 없으니..
어이가 없어서 남긴다. 여튼 겨우 한건 해결...
2019/02/27 11:31 2019/02/27 11:31
삼성 덱스에서 앱을 시동하면, 모바일 기기 기준으로 실행된다.
그런데 아시다시피 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
지문인식 기능을 개발할 일이 있어서 개발을 완료했는데, 뒤늦게 다른 기기에서 동작을 안하는걸 발견했다.
분명히 테스트 기기 (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
여러가지 이유가 있을테지만 나는 See console 해도 아무 내용이 없었다.
벙쪄서 며칠보다가... 어이가 없이 문제를 찾아냈는데

JAVA 가 깨져서 그랬다 -_-

자바가 깨져도 놀랍게도 안드로이드는 빌드가 가능했고....
기기에서 돌리니 굳이 필요가 없던것이었다. 그러다 release 는 jre를 이용해서 proguard를 돌리니까 see console에러가 나오고..
cmd에서 java 가 제대로 동작하나부터 확인하고 시작하자... 어이가 없네 진짜
2018/01/17 14:24 2018/01/17 14:24
원래 intent를 넘겨줄때 file:/// 이런식으로 absolute path 를 넘겨주었으나 왠지 모르겠지만 Nougat 때부터 content:// 형태로 넘겨주기 시작했다. 때문에 기존 방법으로는 path를 얻을 수 없다.

이때 content:// 를 파싱(??) 하면 정보를 얻을 수 있다.

public String getFileName(Uri uri) {
 String result = null;
 if (uri.getScheme().equals("content")) {
   Cursor cursor = getContentResolver().query(uri, null, null, null, null);
   try {
     if (cursor != null && cursor.moveToFirst()) {
       result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
     }
   } finally {
     cursor.close();
   }
 }
 if (result == null) { 
   result = uri.getPath();
 }
 return result;
}


요점은 cursor 를 이용해 query 를 날려 의미하는 바를 알아내는 것이다.
제대로 안하면 커서 row에서 에러 나오고 쌩 고생을 할 수도있는데 요거면 잘된다.
혹시 전체 덤프가 필요하다면 datautils 의 dump를 이용하면 모두 로그로 찍어볼 수도 있다.
2017/03/13 15:44 2017/03/13 15:44
Marshmallow 는 여러모로 똥을 던져주는 버전같다.
이번에는 단순히 Intent로 앱을 호출했는데 스크린 오버레이 감지가 발생하는 경우를 겪게 되었다

흔히 다음과 같은 경우에 발생한다.
유저 편의를 위한답시고 Toast로 파일을 실행합니다.. 따위의 안내문을 출력하게 되는데, 안드로이드는 정말 똑똑한 머신이라 Toast를 출력하고 있는앱을 현재 실행하고 있는 앱으로 판단한다

때문에 이때 intent를 호출하거나 권한 승인 다이얼로그가 출력되면, 안드로이드는 이 새로운 손님을 화면위에 플로팅하는 오버레이앱이라고 판단해버린다. 즉, intent를 넘겨줄때는 반드시 모든 Toast가 종료된 후 실행되어야 한다.

화면 오버레이 감지됨을 피하는 방법

1. 모든 Toast가 꺼진 후 intent를 호출
2. 안내 Toast를 모두 제거

http://stackoverflow.com/questions/35453759/android-screen-overlay-detected-message-if-user-is-trying-to-grant-a-permissio?answertab=votes#tab-top

2017/02/28 14:40 2017/02/28 14:40
이번에 외부 저장소의 파일 헤더를 수정하다가 하다가 알게된건데, Android 에서 SD card에 저장된 파일을 핸들링하려니까 권한이 없다며 진행되지 않았다.

의아하게 여겨 바로 한 일은 외부 저장소의 권한을 살펴본 일인데, 멀쩡히 권한이 존재할 것 이다.

대개, 이런식으로 되어 있을 것이다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" ></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" ></uses-permission>


꼼꼼한 개발자라면 해당 권한이 위험한 권한(dangerous permission)임을 인지하고 M 버전부터 처리코드를 넣어 다음과 같이 유저에게 request permission을 하고 있을지도 모른다.

                requestPermissions(new String[] {
                                     Manifest.permission.READ_EXTERNAL_STORAGE, 
                                     Manifest.permission.WRITE_EXTERNAL_STORAGE
                                   }, MY_PERMISSION_REQUEST_CODE)


헌데 외부 저장소 권한을 설정하였는데, 왜 SD Cad에 저장된 파일을 컨트롤할 수 없는걸까? 그건 바로 Android의 기괴한 정책때문에 그렇다.

먼저, 본론으로 들어가기전에
알아두어야 될 점은 Android에서 얼마나 이상하게 SD Card를 다루느냐이다.

먼저, Android에서 말하는 External Storage는 실제 External Storage (SD Card)를 의미하지 않는다.
여기서 가리키는 저장소는 '완전히 따로 관리되는 내부' 메모리와, 내부에 있는 '일반 파일 영역'을 의미한다.

이에 대한 근거는,

File Environment.getExternalStorageDirectory()


로 경로를 반환받을시, SD card를 가리키지 않기 때문이다. 어딜 가르키느냐? 일반 파일 영역을 나타내준다.
정말 이해가 안되는 일이지만 SD Card를 가리키는 경로는 제조사별로 다르기때문에 알아낼 도리가 없다.
굳이 알아내보려면 이런 느낌으로 써야한다.

filepath.contains('mnt/sdcard').. ? sd card!
filepath.contains('mnt/extCard')..? sd card!
filepath.contains('mnt/ext_sd')..? sd card!


정말 어이가 없는 일이다. 이건 제조사별로 다르다고 치고, 본론으로 돌아가서, 왜 SD Card 내에 파일을 쓰거나 수정할 수 없는걸까?
그런데, 지금 말하는 이야기가 얼토당토하지 않게 보이는 사람도 있을 것이다. "나는 잘되는데 뭔소리지?"

먼저, Froyo와 Gingerbread(2.2~2.3)의 Android는 권한 체크에 그리 꼼꼼하지 않았다.
그래서 External Storage_Write/Read 권한만 있어도 SD Card를 얼마든지 컨트롤 할 수 있었다.
그러다가, HoneyComb(3.0) 이상에서 추가 권한을 요구하게 되는데, 바로 우리를 곤경에 빠트리게 할,

WRITE_MEDIA_STORAGE 라는 권한의 등장이다. 이 문제는 LOLLIPOP 까지 지속된다. (5.0)

이 권한을 그럼 명세하면되지 않느냐? 라고 물을 수 있지만 해당 권한은 시스템권한으로, 일반 유저가 줄 수 없는 권한이다.
- 제조사에서는 제조사 기본앱에 이 권한을 주어 설치해놓은 경우도 존재함

3.0 부터 5,0 버전을 사용하는 유저들은 루팅후, SDfix 라는 이상한 앱을 설치해 그룹 퍼미션을 줘가며 사용해야만 했었던 것이다.
앱이 하는 역할은 다음과 같다.

<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
    <group gid="sdcard_r" />
    <group gid="sdcard_rw" />
    <group gid="media_rw" />
</permission>


하지만 일반 논루팅 유저들은 해당 권한을 줄 수 없으므로, 결국 앱을 이용한 SD Card Write Access는 가질 수 없는 것이다.
그러다가 놀랍게도, Marshmallow(6.0)에서 부터는 External Storage 권한을 위험한 권한으로 규정하면서, 유저 추가 동의를 받을 경우 쓸 수 있게 바꿔버린것이다. 오마이 갓....

고로 결론은 다음과 같다. 이를 우회할 방법은 존재치 않으니 빨랑 포기하시라...
2017/01/17 17:42 2017/01/17 17:42