안드로이드 스투디오에 내장된 JRE에 인증서 추가하기

안드로이드 스투디오에 내장된 JRE에 인증서를 추가해보자.

$ keytool -import -noprompt -trustcacerts -alias aliasname -file "<인증서 파일>" -keystore "<안드로이드 스투디오 설치 경로>\Android Studio\jre\jre\lib\security\cacerts" -storepass changeit

안드로이드의 BuildConfig 활용

안드로이드는 앱을 빌드하는 과정에서 여러 파일을 자동으로 생성한다. BuildConfig 클래스도 그 중 하나로, 현재 빌드에 관한 정보를 상수 필드로 갖고 있어 코드에서 직접 참고할 수 있다.

package me.sunphiz.kotlin.myapplication;

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "me.sunphiz.kotlin.myapplication";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}
if( BuildConfig.DEBUG )
{
    // 내 코드
}

파일은 /build/generated/source/buildConfig/.. 이하에 위치하고, <application id>.BuildConfig 의 이름을 갖는다.

기본 상수 외에 build.gradle를 통해 내가 필요한 필드를 직접 추가할 수도 있다. 이 상수는 빌드 타입에 따라 buildType 뿐 아니라 defaultConfig, productFlavors에도 선언이 가능하다. buildConfig를 여러 개 선언하다보면 번거로워진다. 이 때 Groovy의 맵 자료 구조 iteration을 이용하면, 아래처럼 buildConfig 값을 맵 형식으로 따로 정리할 수 있다.

ext {
    extraStringBuildConfig = [ NAME : '"Dog발자"' ]
    extraBooleanBuildConfig = [ KOREAN : 'true' ]
}

android {
    defaultConfig {
        ...

        extraStringBuildConfig.each{ k, v ->
            buildConfigField 'String', k, v
        }

        extraBooleanBuildConfig.each{ k, v ->
            buildConfigField 'boolean', k, v
        }
    }
    ...
}

그 밖에

참조

Glide 이미지 라이브러리 커스터마이징

Glide의 커스터마이징은 공식 문서(영문)에 더 자세히 설명되어 있다. 내게 필요한 기능이 무엇인지 참고하고, 더 자세한 내용은 꼭 공식 문서를 보자.

Glide는 Fresco, Picasso, Universal Image Loader 등과 함께 안드로이드에서 손 꼽히는 이미지 라이브러리다. Glide를 리용하면 원격지(remote)/로컬(local) 이미지를 가져와 화면에 표시할 수 있다. 가져온 이미지는 캐싱을 통해 로딩 속도를 개선할 수 있으며, 필요하다면 이미지 모서리 깎기(rounding)같은 재처리와 애니메이티드 gif도 표시할 수 있다. 따로 HTTP 라이브러리를 쓰지 않고 동작하지만, Volley나 OkHttp 라이브러리와도 호환 동작할 수 있다. 이제는 사라진 범프(Bump) 앱에서 사용할 목적으로 개발/적용한 것이 이 라이브러리의 시작으로 알려져 있다.

Glide의 사용법은 쉬울 뿐 아니라 공식 문서(영문)가 예시와 함께 친절하게 작성되어 있다. 그러므로, 여기서는 기본적인 사용방법 보다는 Glide의 AppGlideModule를 통해 Glide의 동작을 커스터마이징을 할 수 있는 고급 옵션들에 대해 살펴보자.

Glide의 고급 설정(configuration)을 위해서는 준비가 필요하다.

  1. AppGlideModule 추상클래스의 구현체 추가
  2. @GlideModule 어노테이션을 구현체에 선언
  3. 구현체 컴파일을 위해 build.gradle에 Glide 어노테이션 프로세서 추가
  4. 프로가드 설정에 AppGlideModule 클래스의 -keep 선언 추가

준비가 끝나면, 아래와 같이 구현체의 applyOptions() 안에 고급 설정을 추가할 수 있다.

@GlideModule
public class YourGlideModule extends AppGlideModule
{
    @Override
    public void applyOptions( Context _context, GlideBuilder _builder )
    {
        // 고급 설정 추가
    }
}

메모리 캐시

GlideBuilder.setMemoryCache()를 통해, 메모리 캐시 크기를 정할 수 있다. 캐싱할 화면의 갯수를 정수로 지정하거나 직접 캐시 크기를 지정할 수 있다. 화면의 갯수로 지정할 때는  앱의 가장 긴 화면을 염두하여 지정하면 같은 이미지를 원격지에서 반복적으로 로딩하지 않고 캐싱할 수 있을 것이다.

비트맵 풀

GlideBuilder.setBitmapPoolScreens()를 통해, 비트맵 캐시 크기를 정할 수 있다. 정하는 방법은 메모리 캐시와 유사하다.

디스크 캐시

GlideBuilder.setDiskCache()를 통해, 디스크 캐시를 위한 폴더 이름과 디스크 캐시 폴더의 최대 용량를 정할 수 있다. 폴더의 기본 이름은 ‘glide’, 용량은 250mb이다.

리퀘스트 옵션 기본 값 변경

GlideBuilder.setDefaultRequestOptions()에 RequestOptions 객체를 전달하는 방식으로 변경할 수 있다. Glide.with() 메소드에서 반환하는 RequestManager.apply()를 통해 매 이미지 요청마다 설정할 수도 있지만, 여기서 설정하면 모든 요청의 기본 값으로 적용된다.

이미지 저장 방식(원본만, 재처리 후 사본 만, 모두)이나, 출처(원격지만, 로컬만, 모두), 이미지의 decode 포멧 등을 명시적으로 선언할 수 있다.

로그

GlideBuilder.setLogLevel()을 통해, 로그 레벨을 조절할 수 있다. 개발할 때는 Log.DEBUG, 공개할 때는 Log.ERROR 정도가 적당해 보인다.

모든 설정을 추가한다면, 아래와 같은 코드가 될 수 있다.

@GlideModule
public class YourGlideModule extends AppGlideModule 
{
    @Override
    public void applyOptions( Context _context, GlideBuilder _builder )
    {
        // 메모리 캐시
        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).setMemoryCacheScreens(2).build();
        _builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));

        // 비트맵 풀
        int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
        _builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));

        // 디스크 캐시
        int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
        _builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));

        // 리퀘스트 옵션 기본 값
        _builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.RGB_565).disallowHardwareBitmaps());

        // 로그 레벨
        _builder.setLogLevel(Log.DEBUG);
    }
}

그 밖에

참조

Volley의 Apache HTTP client 라이브러리 참조 제거

Volley는 2013년 구글에서 공개한 안드로이드 네트워크 라이브러리다. 구글 플레이 스토어 팀에서 개발/적용 후 공개한 것이 Volley의 시작으로 알려져 있다. 지금은 인기가 예전만 못하지만, 공개 당시에는 가장 좋은 네트워크 라이브러리 중 하나였다. Volley에 대한 자세한 소개는 공식 트레이닝 사이트(한글)를 참조하자.

공식 Apache HTTP client 라이브러리(이하, 라이브러리)는 자바 진영의 대표적인 HTTP 라이브러리로, 수많은 개발자를 네트워크와 관련된 혼란에서 구제했다. 안드로이드도 이 라이브러리를 이식해주어, 안드로이드 앱 개발자들에게 추가적인 학습 없이도 네트워크 관련 기능을 쉽게 쓰도록 해주었다.

다만, 지금와서 보면 원래 라이브러리의 어느 버전을 이식한 것인지 불분명하고 원래 라이브러리는 오래 전에 Apache HttpComponents로 이름까지 바뀌었다. 배터리와 데이터 사용량 등에 민감하고 네트워크 상황이 빈번히 바뀌는 모바일 환경의 특징도 충분히 반영하지 못한 것 같다. 정확한 이유는 찾지 못했으나 개인적으로 폭발적인 안드로이드 성장세에 최대한 빨리 HTTP 관련 라이브러리 지원을 하고자 했던 당시 상황이 영향을 준 것 같다. 이와 관련하여, 안드로이드의 HTTP 라이브러리 비교분석 글을 읽어보면 좋다.

앞서 언급한 이유인지 모르지만, 안드로이드는 M(6.0)과 P(9.0) 두 차례에 걸쳐 이 라이브러리 지원 종료를 예고했다. 지원 제거가 곧 사용 불가를 의미하는 것은 아니어서, M 이상은 build.gradleP 이상은 AndroidManifest.xml 에 명시적 선언을 하면 여전히 사용할 수 있다. 하지만, 안드로이드는 기능적으로 개선된 HTTPUrlConnection 사용을 권장한다.

이런 안드로이드의 정책에 맞춰 Volley도 minSdkVersion이 9 이상이면 v1.1.0부터 라이브러리를 참조하지 않는다. 참조할  필요가 없으니 명시적 선언도 제거할 수 있다. Volley를 사용하고 있다면 최신버전을 사용하고 라이브러리 참조도 제거해보자.

그 밖에

  • Volley는 장기적으로 조건부 참조 코드도 제거할 것이라 한다. Volley 라이브러리 업데이트가 예전만큼 활발하지 않아 언제 반영될지는 알 수 없지만 말이다.

참조