시스템 폰트 크기 변경시 UI 이슈 대응하기

대부분의 안드로이드 사용자의 경우에는 폰트의 크기를 default 사이즈로 사용해서 특별히 문제가 없지만, 나이가 드신 분들이나 작은 글자의 인식이 불편해서 글자의 크기를 크게(최대로) 해서 보시는 분들도 있다. 이 경우에는 앱에서 이 경우를 대비해서 대응하지 않으면 글자의 위/아래가 잘리는 경우를 볼 수 있다.

우선 폰트의 크기를 설정 앱에서 변경해 보자. 갤럭시를 기준으로 살펴보면 Settings > Display > Font size and style 에서 아래와 같이 폰트의 크기를 변경할 수 있다.

다음으로, 위 화면과 같이 폰트의 크기를 최대로 변경한 경우, 앱에서 어떻게 보이는지 살펴보자. 예로 아래의 화면과 아래의 코드가 이 경우에 해당한다.

그리고, 위 화면을 보여주는 텍스트 뷰의 간략한 코드는 아래와 같다.

<TextView
android:id="@+id/fg_docs_item_detail"
android:layout_width="0dp"
android:layout_height="28dp"
..... />

다음으로, 이 문제를 해결하기 위한 방안을 살펴보자. 간단하게 UI(XML) 코드를 아래와 같이 개선하면 된다. android:layout_height은 글자 크기에 따라서 커질 수 있게 처리(wrap_content)하고, android:minHeight은 기존의 컴포넌트 크기로 고정한다. 그리고, 아래 UI를 포함하는 뷰 그룹(Linear, Relative, Fragme, Constraint)들도 아래와 같이 처리하면 안드로이드 시스템 폰트의 크기를 변경해도 앱 화면의 UI가 잘리지 않게 된다.

<TextView
android:id="@+id/fg_docs_item_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="28dp"
..... />

마지막으로, 위 코드를 적용한 앱의 화면을 아래에서 볼 수 있다. 이 화면에서는 글자가 커지긴 했지만, 잘리지 않고 잘 보이는 것을 알 수 있다.

안드로이드 음성 검색에서 언어 선택하기

안드로이드 앱에서 음성 검색(Voice Search)을 하는 방법을 아래와 같은 코드로 간단하게 실행할 수 있다.

private static final int SPEECH_REQUEST_CODE = 0;

// Create an intent that can start the Speech Recognizer activity
private void displaySpeechRecognizer() {
	Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
	intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
	// Start the activity, the intent will be populated with the speech text
	startActivityForResult(intent, SPEECH_REQUEST_CODE);
}

// This callback is invoked when the Speech Recognizer returns.
// This is where you process the intent and extract the speech text from the intent.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (requestCode == SPEECH_REQUEST_CODE && resultCode == RESULT_OK) {
		List results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
		String spokenText = results.get(0);
		// Do something with spokenText
	}
	super.onActivityResult(requestCode, resultCode, data);
}

위 코드는 https://developer.android.com/training/wearables/apps/voice 에서 확인 할 수 있고, 안드로이드 OS에 설정한 언어를 기반으로 인식한다. 위 코드를 실행하면 아래와 같이, 시스템 언어에 따라서 영어, 한국어를 인식하는 것을 알 수 있다.
 
– 안드로이드 OS 언어 설정에 따른 음성 검색 화면

이제 많은 앱들이 앱 자체에서 언어를 동적으로 변경할 수 있는 기능을 제공하고 있고, 이 경우에 안드로이드 OS의 언어 설정에 따른 음성 검색이 아니라 앱에서 사용하는 언어의 음성 검색이 필요하게 되었다.

위는 개인적으로 만들어서 서비스하는 오피스 리더 앱(https://play.google.com/store/apps/details?id=net.sjava.officereader) 에서 언어를 변경할 수 있는 화면이다. 이 상황에서 언어를 변경해도 음성 검색은 시스템의 언어를 기준으로 검색을 하기 때문에, 앱의 언어를 한국어로 변경했지만 음성 검색에서 영어를 인식언어로 사용하게 된다. 그래서, 특정 언어를 기준으로 인식을 요청하기 위해서는 아래의 파라미터 값에 언어와 나라의 값을 알려주면 된다.

intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, “ko-KR”);

그러나, 설정에서 변경하는 값이 언어이지, 나라 위치가 아니다. 그리고, 언어별로 사용할 수 있는 나라들이 많이 존재하는 경우가 일반적이기도 하다. 안드로이드 5.0.1의 로케일(https://github.com/championswimmer/android-locales)을 살펴보면, 조금씩 다른 경우가 많겠지만 한 언어를 사용하는 국가가 많다. 그래서, 앱에서 언어를 변경하는 경우, 그 언어의 대표 값을 인식할 수 있게 해서 음성 검색시 나라의 위치를 확인하지 않아도 동작해야 하고, 아래 코드로 앱에서 설정한 언어의 대표 언어를 가져와서 “-“를 추가해서, 대표 언어로 인식하게 할 수 있다.

// Create an intent that can start the Speech Recognizer activity
private void displaySpeechRecognizer(Context context) {
	Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
	intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
	LocaleList localeList = context.getResources().getConfiguration().getLocales();
	if(localeList.size() > 0) {
		String language = localeList.get(0).getLanguage();
		intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language +"-");
	}
	// Start the activity, the intent will be populated with the speech text
	startActivityForResult(intent, SPEECH_REQUEST_CODE);
}

이제 위 코드를 사용하면, 앱에서 언어를 변경한 경우에 쉽게 변경한 언어에 맞게 음성 검색을 실행할 수 있다.

Waiting For Debugger 다이얼로그 이슈

안드로이드 스튜디오에서 앱을 디버그 모드로 실행하다가, 일반 모드를 실행하는 경우, 간혹 아래와 같은 화면을 볼 수 있다. 그리고, 일반 모드로 실행할 수 없는 상태가 된다.

debug dialog

위 이미지는 https://stackoverflow.com/questions/51489243/waiting-for-debugger-without-be-on-debug-mode 에서 링크한 이미지이다.

이 경우에, 아래의 명령으로 디버그 앱을 삭제(?)하고 실행하면 정상 실행되는 것을 확인할 수 있다.

adb shell am clear-debug-app

 

 

안드로이드 앱 테스트 서비스

안드로이드 앱을 개발하고 서비스하다 보면, 특정 기기에서만 문제가 발생하는 경우를 종종 볼 수 있다. 이 문제는 해당 기기가 없으면 재현하기도 힘들고, 결국 디버깅하기도 어렵다. 큰 회사의 경우에는 테스트 기기를 다양하게 보유하고 있어서 문제가 없지만, 필자의 경우처럼 개인 개발자들은 현실적으로 테스트 기기를 여러 대 구매하기가 어렵다. 그래서 찾아보니 앱을 온라인에서 쉽게 테스트할 수 있는 무료 서비스가 2개 정도 있고, 아주 유용하기에 이 온라인 테스트 서비스를 살펴보자.

1. SMAC 온라인 앱 테스트 도구

이 도구는 한국 모바일 산업 연합회라는 곳에서 운영하는 스마트 모바일 앱 개발자 지원센터에서 서비스하고 있다. 테스트 할 수 있는 단말기가 국내 안드로이드 기기 제조사, 소니, 그리고 애플의 몇 개의 기기에서 자신의 앱을 확인할 수 있다. 아래 링크로 사용할 수 있다.
https://apptest.appvillage.or.kr/service/index.do


– 앱 테스트 도구를 실행한 화면

위 화면은 온라인 앱 테스트 도구에서 삼성 갤럭시 S8 기기를 실행한 화면이다. 위아래 스크롤로 사용할 수 있는 기기를 확인할 수 있고, 원하는 기기를 선택하고 “시작하기” 버튼을 클릭하면 된다.

2. 삼성 리모트 테스트 렙(Remote Test Lab)

개발한 앱을 삼성의 모바일 제품군인 갤럭시(Galaxy), Z, 와치(Watch) 에서 테스트 할 수 있다. 갤럭시의 최신 제품인 Z 플립(Z Flip)이나 폴드(Fold) 제품은 가격이 고가이기에 개인 개발자가 앱을 테스트하기 위해서 구매하기 어렵기에 이 서비스는 개인 개발자들에게 매우 유용하다. 아래 링크로 연결할 수 있다.
http://developer.samsung.com/rtlLanding.do


– 삼성 리모트 테스트 렙의 갤럭시 탭 화면

위 화면은 갤럭시 탭에서 테스트할 수 있는 일부 기기를 보여준다. 이 외에도 갤럭시 노트 10, S9, S8, S7, S6, S5 및 탭 S4, S3 등을 테스트할 수 있게 지원한다. 위 화면에서 왼쪽의 Z를 선택하면 타이젠 기반의 앱을 확인할 수 있다. 그리고, 와치를 선택하면 갤럭시 와치, 기어, S3, 그리고 기어 핏 2에서 테스트할 수 있게 지원한다.

   
– 갤럭시 Z 플립에서 테스트하는 화면

위 화면은 갤럭시 Z 플립 기기를 실행한 화면이다. 첫 번째 화면은 플립을 접은 모습이고, 두 번째 화면을 플릭을 연 화면이다.

위 2개의 서비스에 대한 장/단점을 살펴보면 아래와 같다.

– SMAC 온라인 앱 테스트 도구는 테스트 도구를 실행하면 여러 기기(삼성 일부, LG, 그리고 소니 등)를 시작해서 테스트 할 수 있고, iOS/iPad도 지원하는 것이 강점이다. 그러나, 최신 안드로이드 기기를 지원하지 않는 것이 단점이다.

– 삼성 리모트 테스트 렙은 삼성에서 만들고 있는 다양하고 최신의 기기에서 테스트할 수 있게 지원하는 것이 강점이다. 그러나 매번 자바 웹 스타트 파일(jnlp)을 다운로드 하게 해서 여러 기기에서 테스트하기에는 좀 불편하다.

위 2가지의 앱 테스트 서비스를 사용하면, 개인 개발자가 많은 테스트 기기를 보유하지 않아도 테스트 및 디버깅을 할 수 있어서 아주 유용하다.

안드로이드 키오스크(Kiosk) 앱 개발 (3/3)

앞의 과정(안드로이드 키오스크 앱 개발 1/3, 안드로이드 키오스크 앱 개발 2/3)에서 안드로이드 앱을 기기의 키오스크 모드로 동작시키기 위한 프로그래밍 방법을 살펴봤다. 여기에서는 앞의 과정으로 만든 앱을 실 기기에 배포하는 방법을 살펴본다. 앱을 프로비저닝해서 실 기기에 배포하는 방법(버전별 지원 방법 확인)으로 NFC와 QR 코드로 앱을 설치하는 두 가지 방법이 널리 쓰이고, 여기에서 QR 코드를 사용하는 방법을 살펴보자.

전체 과정은 앱을 빌드하고, 빌드된 APK를 웹 서버에 업로드하고, 이 정보를 바탕으로 QR 코드를 생성하고, 마지막으로 QR코드를 사용해서 프로비저닝된 APK를 실제 기기에 설치하면 된다. 아래에서 개별 과정을 살펴보자.

1. 앱 빌드

릴리즈 버전의 앱은 아래의 2가지 방법으로 빌드하면 된다.

1.1 안드로이드 스튜디오의 Build > Generate Signed Bundle/APK 메뉴를 선택해서 빌드한다.

1.2 터미널(Terminal) 탭에서 아래의 명령으로 APK를 빌드한다.

./gradlew aR 

2. 웹 서버 및 ngrok 툴 설정

이제 빌드한 앱을 다운로드할 수 있는 엔드 포인트를 만들어보자.

2.1 웹 서버

아래 주소에서 간단한 바로 실행할 수 있는 자바 웹 서버를 다운로드 한다.
http://www.jibble.org/miniwebserver/

그리고, 아래의 명령으로 자바 웹 서버를 실행한다.

java -jar SimpleWebServer.jar

2.2 ngrok 툴 설정

아래 주소에서 ngrok 툴을 다운로드 받아서 설치한다.
https://ngrok.com/

내/외부에서 쉽게 도메인을 치고 들어올 수 있게 지원하는 툴이다. 이 툴의 설명을 보면, “secure introspectable tunnels to localhost”로 안전하게 로컬호스트로 터널링을 지원하는 도구라는 것을 알 수 있다.

아래이 명령으로 외부에서 http(s)://xxxxx.ngrok.io 도메인으로 접속할 수 있게 한다.

ngrok http 80 


– 웹 서버와 ngrok 툴 설정화면


– 웹 브라우저로 ngrok 툴이 설정한 주소로 접근한 화면

3. QR 코드 생성

이제 앱을 프로비저닝하는 QR 코드를 만들어 보자. APK 프로비저닝하기 위해서 QR 코드에 입력해야 하는 값은 아래와 같은 같다.

{
"android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME":"net.sjava.examples.kiosk/.KioskDeviceAdminReceiver",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION":"https://745b0d80.ngrok.io/app-release.apk",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM":"xxxx-xxxx-xxxxxx-xxxxxxxx_xxxx",
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION":true,
"android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED":true,
}

– QR 코드 입력값

위 코드에서 PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME 값은 패키지와 관리자 리시버 클래스 이름이다. PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION은 APK 파일을 다운로드 받을 주소이다. PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM은 APK의 CHECKSUM 값으로 아래의 명령을 사용해서 개발한 앱의 CHECKSUM 값을 구할 수 있다.

apksigner verify -print-certs app-release.apk | grep -Po "(?<=SHA-256 digest:) .*" | xxd -r -p | openssl base64 | tr -d '=' | tr -- '+/=' '-_'

PROVISIONING_SKIP_ENCRYPTION나 PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED은 이름에서 알 수 있듯이 암호화와 기존 시스템앱을 모두 사용할 수 있게 설정한다는 것이다.

위의 값으로 http://down-box.appspot.com/ 에서 위의 과정으로 만들어진 값을 사용해 아래와 같이 QR 코드를 쉽게 만들 수 있다.
위에서 샘플로 만들어본 QR 코드는 http://down-box.appspot.com/qr/GH1ayZg9 주소에서 확인할 수 있지만, 실제 기기에서는 동작하지 않는다.

4. QR 코드로 APK를 관리자 앱으로 설치

테스트할 수 있는 안드로이드 기기를 공장 초기화(Factory Reset)한다. 그리고, 첫 부팅 화면에서 시작 버튼이나 다른 버튼을 사용해서 안드로이드 기기를 시작하지 말고, 바탕 화면을 연속해서 6~7번 탭을 하면 QR 코드를 읽을 수 있는 앱을 실행하게 된다. 또는 안드로이드 7을 사용중인 경우에는 Wifi에 연결한 뒤에 QR 코드를 읽는 앱을 다운로드 해서 실행하는 경우가 있기에 조금 기다리면 QR 코드를 읽는 앱을 볼 수 있다.

이 앱을 사용해서 프로비저닝된 앱을 설치하면, 이 앱은 소유자 권한으로 설치가 되고 이 앱을 통해서 비교적 안전하게 키오스크 모드로 동작하는 앱을 배포할 수 있다.

Reference

https://developers.google.com/android/management/provision-device
https://github.com/googlesamples/android-testdpc