Upload Android Library into Gradle with Artifactory

Bintray 를 서비스하는 JFrog 에서 아키펙트 패키지(Gradle 나 maven, docker 등 저장소)를 관리하는 소프트를 제작하는데, 그것이 바로 Artifactory 이다. 그 중 Pro 버전은 유료지만, oss라 하여 오픈 소스 버전 (즉 커뮤니티 버전) 이 있는데, 이 것을 사용해서 자체적인 Gradle 저장소를 만들 수 있다.

이 글에서는 VPS 환경에서 자체적인 Gradle 저장소를 만들고, 배포하는 방법을 작성하려 한다.

주의할 점으로, 이 글에서는 Docker 설치나 환경 설정에 대해 언급하지는 않는다.

서버 환경

Vultr Cloud Compute의 $10 서버, 즉 40GB SSD / 2GB RAM / 2TB Bandwidth / 1 CPU(Skylake CPU) 를 사용헀고, OS 는 Ubuntu 18.04.1 LTS 이다.

추가적으로, Artifactory 를 안정적으로 Serve 하기 위해 Docker, PostgreSQL 를 사용했다.

Docker-compose 준비

Artifactory 도커 이미지에는 standalone 으로 돌아갈 수 있게 하는 프로그램이 들어가 있기 때문에, 아래의 명령어 1줄이면 쉽게 구동할 수 있다.

docker run --name artifactory -d -p 8081:8081 docker.bintray.io/jfrog/artifactory-oss:latest  

다만 이 방법은 여러 설정을 하려면 명령어가 길어지고, 여러 개의 컨테이너를 동시에 사용해야 될 경우 각각 하나마다 동작 상태를 확인해야 하는 문제가 있어 Docker-compose 를 사용하여 임의의 설정 파일을 만들고 설정 파일을 docker 에 올리는 방법을 사용한다.

여기서 Docker-compose 란 여러 개의 컨테이너를 한 데에 묶어 컨테이너를 순차적으로 생성하는 역할을 한다. Artifcatory 를 구동하기 위해서는 Artifactory 컨테이너와 DB 역할이 되는 PostgreSQL 컨테이너가 필요하기 때문에, 일일히 run 으로 돌리기 보다는 Docker-compose 를 이용해 한번에 관리하려 한다.

다행히도, JFrog가 Github 에 Docker-compose 예제 파일을 올려두어 모든 것을 다 작업할 필요는 없지만, 위 서버 환경에서 적용했을 때 문제가 있어 아래에 정리하려 한다.

Artifactory 구동에 필요한 환경 설정

구동에 필요한 환경 설정 작업은 다음과 같다.

  • 데이터 폴더 생성
  • 기본 설정 파일 복사
  • 권한 설정

데이터 폴더 생성

# mkdir -p /data/postgresql
# mkdir -p /data/artifactory/etc
# mkdir -p /data/nginx/conf.d
# mkdir -p /data/nginx/logs
# mkdir -p /data/nginx/ssl

sudo 권한으로 접근해 위 명령어를 실행하면 된다.

기본 설정 파일 복사

기본 설정 파일에 대해서는 Jfrog/artifactory-docker-examples에 전부 포함되어 있다. 기본 설정 파일 자체를 수정할 필요는 없으니 각각 맞는 경로에 복사하면 된다. 기본 설정 파일의 경로는 이쪽이다.

  1. /data/artifactory 폴더에 access 폴더 안 내용을 삽입한다. 즉, /data/artifactory/access/etc/keys 에 private.key, root.crt 가 있어야 한다.
  2. /data/nginx/conf.d/oss 폴더에 artifactory.conf 를 삽입한다.

권한 설정

Artifactory 6.2.0 부터 artifactory 라는 유저를 생성하여 그 유저만 /data/artifactory 폴더를 접근할 수 있게 변경되었다.

# chown -R 1030:1030 /data/artifactory
# chown -R 104:107 /data/nginx

sudo 권한으로 접근해 위 명령어를 실행하면 된다. 여기서 1030, 104 및 107은 미리 정의된 값으로 사용자에 맞게 수정하면 될 것 같다.

Docker-compose 파일 작성

일반적 문법은 여기서 설명하지 않으나, 기본적인 것을 설명하자면 Docker-compose 의 설정 파일은 yml 확장자를 가지고 있으며, 각 depth 에 컨테이너 이름과 그 정보를 넣는다. 자세한 문법은 Docker-compose version 2 reference 문서를 참고하면 된다.

version: '2'
services:
  postgresql:
    image: library/postgres:latest
    container_name: postgresql
    ports:
     - 5432:5432
    environment:
     - POSTGRES_DB=artifactory
     # The following must match the DB_USER and DB_PASSWORD values passed to Artifactory
     - POSTGRES_USER=artifactory
     - POSTGRES_PASSWORD=password
    volumes:
     - /data/postgresql:/var/lib/postgresql/data
    restart: always
    ulimits:
      nproc: 65535
      nofile:
        soft: 32000
        hard: 40000
  artifactory:
    image: docker.bintray.io/jfrog/artifactory-oss:latest
    container_name: artifactory
    ports:
     - 80:8081
    depends_on:
     - postgresql
    links:
     - postgresql
    volumes:
     - /data/artifactory:/var/opt/jfrog/artifactory
    environment:
     - DB_TYPE=postgresql
     # The following must match the POSTGRES_USER and POSTGRES_PASSWORD values passed to PostgreSQL
     - DB_USER=artifactory
     - DB_PASSWORD=password
     # Add extra Java options by uncommenting the following line
     #- EXTRA_JAVA_OPTIONS=-Xmx4g
    restart: always
    ulimits:
      nproc: 65535
      nofile:
        soft: 32000
        hard: 40000

위 코드를 artifcatory-oss-postgres.yml 라는 이름으로 만들어 서버에 올리면 된다.

Docker-compose 실행

환경 설정도 완료되고, yml 파일도 만들었다면 이제 실행만 하면 된다.

sudo docker-compose -f artifactory-oss-postgresql.yml up -d

위 명령어를 실행하면 postgresql 이미지 와 artifactory 이미지를 pulling 하여 자동으로 받아오고, 실행을 시작한다. up 뒤 -d 옵션을 주는 것으로 사용자가 종료하지 않는 이상 이 컨테이너는 백그라운드에서 계속 구동될 것이다.

이제, 브라우저 등으로 http://localhost 에 접속하면 아래와 같은 창이 나올 것이다.

사진에선 나오지 않아 설명하기 어려우나 처음에 들어가면 초기 설정 팝업이 뜨면서 비밀번호 설정 – 프록시 설정 – 사용 저장소 설정 순서로 나오게 되는데, 프록시 설정은 넘겨도 무방하며, 사용 저장소는 ‘Gradle’ 와 ‘Maven’ 을 선택한다.

여기까지 하면 Gradle 저장소에 대한 구축은 모두 된 것이며, 이제 스튜디오로 넘어와 라이브러리를 업로드하면 된다.

라이브러리 업로드

라이브러리를 업로드하는 것은 다소 어렵지 않게 구성이 가능하다. 업로드 플러그인을 추가하고, 정보를 기재해 명령어를 실행하는 것 뿐이다.

업로드 플러그인 추가

루트 프로젝트의 build.gradle 에 아래 classpath 를 추가한다.

//Check for the latest version here: http://plugins.gradle.org/plugin/com.jfrog.artifactory
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4+"

라이브러리 프로젝트의 build.gradle 에 플러그인을 적용한다.

apply plugin: "com.jfrog.artifactory"
apply plugin: 'maven-publish'

프로젝트 정보 기재

플러그인을 정의한 곳 밑에 변수를 추가한다.

def groupId = "com.github.windsekirun"
def version = "1.0.0"
def artifectId = "AwesomeLibraryForDebug"

def Properties properties = new Properties()
properties.load(project.rootProject.file("local.properties").newDataInputStream())

groupId, version, artifectId 는 각각 그룹, 버전, 아키펙트 이름을 나타낸다. gradle 의존성 문구의 규칙 또한 그룹:아키펙트 이름:버전 이므로 위 정보를 가지고 올리면 com.github.windsekirun:AwesomeLibraryForDebug:1.0.0 이 된다.

그 다음 줄의 Properties 의 경우에 저장소에 올리기 위해 아이디 / 비밀번호를 적어야 하는데, 개인 정보가 코드에 올라가야 되지 않게 해야 하므로 local.properties 에서 불러오도록 코드를 추가하였다. 이와 관련된 자세한 사항은 Insert resValue in gradle file 글에서 볼 수 있다.

플러그인 설정

위에서 프로젝트마다 별도로 설정해야 하는 정보는 모두 기재했으므로, 아래부터는 공통 정보이다.

publishing {
    publications {
        aar(MavenPublication) {
            groupId packageName
            version = libraryVersion
            artifactId projectName

            // Tell maven to prepare the generated "*.aar" file for publishing
            artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
        }
    }
}

artifactory {
    contextUrl = 'ARTIFACTORY URL'
    publish {
        repository {
            // The Artifactory repository key to publish to
            repoKey = 'libs-release-local'

            // personal information will locate at local.properties
            username = properties.getProperty("artifactory.username", "")
            password = properties.getProperty("artifactory.password", "")
        }
        defaults {
            // Tell the Artifactory Plugin which artifacts should be published to Artifactory.
            publications('aar')
            publishArtifacts = true

            // Publish generated POM files to Artifactory (true by default)
            publishPom = true
        }
    }
}

위 코드를 dependencies 문단 밑 (즉 맨 하단)에 넣어주면 된다.

명령어 실행

./gradlew assembleRelease artifactoryPublish

모든 작업이 완료되면, 위 커맨드를 터미널에 실행함으로서 Gradle 저장소에 올라가게 된다.

올라간 정보는 Artifactory 페이지 내 Artifacts 부분에서 찾아볼 수 있다.

위 사진과 같이 aar 와 pom 파일이 같이 올라가고, aar 파일을 클릭했을 때 Dependency Declaration 부분에 정상적으로 나오면 성공이다.

다른 프로젝트에서 불러오기

다른 프로젝트에서 불러오기 위해서는, 모듈의 build.gradle 에 아래 코드를 삽입하면 된다.

repositories {
    maven { url "ARTIFACTORY_URL/list/libs-release-local/" }
}

dependencies {
    implementation "com.github.windsekirun:AwesomeLibraryForDebug:1.0.0"
}

참고로 여기서 예제로 들은 AwesomeLibraryForDebug 는 존재하지 않으므로 시도하지 않아도 된다.

Android Pie (API 28, 9.0) 지원 사항

2018년 11월 기준으로 신규 / 업데이트 앱은 Android Oreo (API 27, 8.0 – 8.1) 을 targetSDKVersion 으로서 지원해야 되므로 최소 2019년 중반 까지는 Andorid Pie 에 대한 지원이 되어야 합니다.

현재 구글 픽셀 시리즈, 에센셜, 엑스페리아 XZ3 에 적용되었으며 LG V40 ThinQ 및 삼성 갤럭시 S10에도 적용 예정으로 발표되었습니다. 삼성 갤럭시 S8의 경우 ‘메이저 OS 2회 업데이트’ 정책에 따라 이번이 마지막 지원이 됩니다. (7.0 -> 8.0 -> 9.0)

참조 문서

Andorid Pie 에서 실행되는 모든 앱에 적용되는 지원 사항

아래 사항은 Android Pie에 구동되는 모든 앱에 해당되며, 이번 지원 사항에는 아래와 같은 주요 포인트를 가지고 있습니다.

  • 전원 관리 – 앱 대기 버킷, 배터리 세이버 개선
  • 백그라운드에서의 센서 (마이크, 카메라, 가속도계, 자이로스코프) 엑세스 제한
  • 통화 로그 액세스 제한 및 CALL_LOG 권한 그룹 신설
  • 전화번호 액세스 제한
  • 비 SDK 인터페이스에 대한 제한

이 중 개발자가 반드시 내용을 파악하고 있어야 하는 것은 전원 관리비 SDK 인터페이스에 대한 제한 이며 아래부터 중요도 순으로 내용을 설명합니다.

비 SDK 인터페이스에 대한 제한

먼저, 비 SDK 인터페이스 란 공식 Android SDK의 일부가 아닌 Java 필드와 메서드로 정의할 수 있습니다. 쉽게 말하지면, private 및 protected 접근자를 가지고 있는 필드 및 메서드라 표현할 수 있습니다. 공식 Andorid SDK의 모든 API는 Android 프레임워크의 SDK 문서에 전부 작성되어있으며, 작성되어있지 않은 API의 경우는 비 SDK 인터페이스라 볼 수 있습니다.

기존까지 비 SDK 인터페이스를 사용하려면 Class 클래스의 getDeclearedFieldgetDeclearedMethod 등의 메서드를 사용하여 각각의 FieldMethod 객체를 찾아 직접적으로 실행하는 방법이 흔히 쓰였습니다.

하지만 Android Pie에서 돌아가는 앱은 이러한 방법을 사용했을 때 정확한 객체를 반환하는 대신 NoSuchFieldException, NoSuchMethodException 을 반환합니다. 또한, getDeclearedFields, getDeclearedMethods 는 이러한 비 SDK 인터페이스가 제외된 결과만 반환합니다. 마찬가지로 Reflection을 제외하고도 JNI의 env->GetFieldID() , env->GetMethodID() 도 같은 결과를 발생시킵니다.

즉, 직접적인 Reflection 및 JNI를 통한 비 SDK 인터페이스의 사용이 모두 제한됩니다.

단, 모든 비 SDK 인터페이스가 사용 불가능한 것이 아닌 동작에 따라 제한을 만들었는데, 그 리스트는 다음과 같습니다.

  • 화이트리스트(모두 허용): SDK
  • 라이트 그레이리스트: 여전히 엑세스가 가능한 비 SDK 메서드 / 필드. 다만 다음 버전에서 이 리스트에 있는 것이 다크 그레이리스트 나 블랙리스트로 이동되지 않는다는 보장이 없습니다.
  • 다크 그레이리스트:
    • targetSDKVersion 가 28 미만일 경우 -> 다크 그레이리스트 인터페이스 사용 허용
    • targetSDKVersion 가 28 이상일 경우 -> 블랙리스트와 같은 동작
  • 블랙리스트: targetSDKVersion 상관 없이 제한되며, 상기된 NoSuchFieldExceptionNoSuchMethodException 의 제한이 적용됩니다. 즉, 플랫폼은 인터페이스가 없는 것 처럼 동작합니다.

여전히 라이트 그레이리스트에 있는 항목은 사용이 가능하지만, 상기된 내용과 같이 다음 버전에서도 작동한다는 보장이 안 되므로 변경할 수 있을 때 모두 변경하는 것이 좋습니다.

현재 앱이 비 SDK 인터페이스를 사용하고 있는지에 대한 판단 방법

StrictMode 클래스의 detectNonSdkApiUse 메서드를 사용하여 검출합니다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    StrictMode.setVmPolicy(
            StrictMode.VmPolicy
                    .Builder()
                    .detectNonSdkApiUsage()
                    .build())
}

비 SDK 인터페이스 사용시 아래와 같은 로그가 출력됩니다.

Accessing hidden method Landroid/gesture/Gesture;->setID(J)V (blacklist, reflection)

StackTrace도 출력됩니다.

D/StrictMode(19092): StrictMode policy violation: android.os.strictmode.NonSdkApiUsedViolation: Landroid/widget/Toast;->mDuration:I
D/StrictMode(19092):    at android.os.StrictMode.lambda$static$1(StrictMode.java:428)
D/StrictMode(19092):    at android.os.-$$Lambda$StrictMode$lu9ekkHJ2HMz0jd3F8K8MnhenxQ.accept(Unknown Source:2)
D/StrictMode(19092):    at java.lang.Class.getDeclaredField(Native Method)
D/StrictMode(19092):    at com.os.operando.non_sdkinterfaces.sample.MainActivity$onCreate$3.onClick(MainActivity.kt:49)
D/StrictMode(19092):    at android.view.View.performClick(View.java:6597)
D/StrictMode(19092):    at android.view.View.performClickInternal(View.java:6574)
D/StrictMode(19092):    at android.view.View.access$3100(View.java:778)
D/StrictMode(19092):    at android.view.View$PerformClick.run(View.java:25883)
D/StrictMode(19092):    at android.os.Handler.handleCallback(Handler.java:873)
D/StrictMode(19092):    at android.os.Handler.dispatchMessage(Handler.java:99)
D/StrictMode(19092):    at android.os.Looper.loop(Looper.java:193)
D/StrictMode(19092):    at android.app.ActivityThread.main(ActivityThread.java:6642)
D/StrictMode(19092):    at java.lang.reflect.Method.invoke(Native Method)
D/StrictMode(19092):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
D/StrictMode(19092):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

StrictMode 는 런타임 상에서의 검출이지만, apk를 대상으로 할 때에는 AOSP가 제공하는 veridex를 사용합니다.

veridex는 shell script 명령으로 실행시킬 수 있습니다. : ./appcompat.sh --dex-file=test.apk

부가적으로 OEM 업체 (삼성, LG) 가 자체 리스트를 추가할 수 있으나, 기본 리스트를 삭제할 수는 없으므로 기본이 되는 AOSP의 리스트에 대한 호환성은 모두 확보해야 합니다.

전원 관리 – 대기 버킷, 배터리 세이버 개선

앱 대기 버킷은 해당 앱이 얼마나 최근에, 자주 사용되는지에 따라 앱의 리소스 요청에 우선순위를 부여합니다. 총 5개의 버킷이 존재합니다.

Active

사용자가 앱을 현재 사용중이면 Active 버킷에 배치됩니다. 예를 들어 액티비티를 시작하거나 포그라운드 서비스를 실행중인 경우, 알림을 클릭한 경우에 해당됩니다.

Working Set

앱이 자주 실행되지만 현재는 활성이 아닌 경우에는 Working Set 버킷에 배치됩니다. 예를 들어, 소셜 미디어 앱은 Working Set에 있을 가능성이 높습니다. 또한 앱이 간접적으로 사용될 경우에도 Working Set 버킷으로 승격됩니다.

Frequent

앱이 매일 실행되는 것은 아니지만 정기적으로 사용되는 경우에는 Frequent 버킷에 배치됩니다.

Rare

앱이 자주 사용되지 않으면 Rare 버킷에 배치됩니다.

Nerver

설치되었지만 한 번도 실행되지 않은 앱은 Never 버킷에 배치됩니다.

시스템은 각 앱을 우선순위 버킷에 동적으로 할당하며, 필요한 경우에는 앱을 재할당합니다. 버킷은 앱이 얼마나 자주 실행되는지, 얼마나 자주 알람을 트리거하는지, 우선순위가 높은 Firebase Cloud Messaging 메세지를 자주 수신하는지에 대해 판별합니다. 이러한 제한은 기기가 배터리 전원을 사용 중인 동안에만 적용되며, 기기가 충전 중일 때는 시스템이 이러한 제한을 적용하지 않습니다.

부가적으로, Doze 허용 목록에 있는 앱은 대기 버킷의 영향을 받지 않습니다.

배터리 세이버 개선에 있어서는 여러 사항이 제한되었는데, 기기 제조업체가 적용되는 정확한 제한 사항을 결정합니다. 예를 들어, AOSP에서는 앱이 유휴 상태가 되기를 기다리는 대신 보다 적극적으로 대기 모드로 전환하며, 백그라운드 실행 제한을 앱의 targetSDKVersion 과 상관 없이 모두 적용하는 등의 행동을 결정합니다.

아래 표는 전원 관리에 대한 제한 표 입니다.

(1) : 작업 제한이 강제적일 경우, 특정 주기마다 10분동안의 작업이 허용됩니다. 10분이 지난 경우에는 모든 작업은 다음 대기열로 미뤄집니다.

(2) : 알람 제한이 강제적인 경우, 모든 알람은 스케쥴된 대기열에 발동되며, 10초동안 작업이 가능합니다.

(3): 네트워크 접근이 제한되었을 경우, 특정 주기마다 10분동안 네트워크를 사용하는 것이 가능합니다.

(4): 우선순위가 높은 FCM 메세지를 수신했을 때에 상한에 도달해있으면 그 이후의 메세지는 보통 우선순위를 가진 메세지로서 처리됩니다.

백그라운드에서의 센서 (마이크, 카메라, 가속도계, 자이로스코프) 엑세스 제한

앱이 마이크, 카메라, 가속도계, 자이로스코프 등의 센서를 사용중인 경우 백그라운드 상태에서는 이 센서의 정보를 받지 못합니다. 앱이 센서 이벤트를 감지해야 하는 경우, 포그라운드 서비스를 사용해야 됩니다.

통화 로그 엑세스 제한

기존에 존재하던 READ_CALL_LOG, WRITE_CALL_LOGPROCESS_OUTGOING_CALLS 권한이 위치하던 PHONE 그룹에서 신설되는 CALL_LOG 그룹으로 이동됩니다. 이 CALL_LOG 그룹은 전화 통화 기록을 보고 전화번호를 식별하는 등과 같이 전화 통화와 관련된 민감한 정보를 엑세스하는 데에 필요한 기능을 제공합니다.

앱에서 통화 로그에 엑세스 해야 하거나 발신 통화를 처리해야 할 경우, Runtime Permissions 요청을 통해 이 권한을 적절히 요청해야 합니다. 이러한 권한은 사용자가 앱에서 전화 통화 기록 정보에 엑세스하지 못하도록 거부할 수 있으므로, 정보에 엑세스하지 못하더라도 이를 적절히 처리할 수 있어야 합니다.

전화번호 엑세스 제한

READ_CALL_LOG 권한을 취득하지 않는 이상, 전화 상태 브로드캐스트 및 PhoneStateListener 클래스에서 전화번호 필드가 비어있게 됩니다. PHONE_STATE 브로드캐스트에서 전화번호를 읽으려면 READ_CALL_LOG 권한과 READ_PHONE_STATE 권한이 모두 필요합니다. 또, onCallStateChanged() 에서 전화번호를 읽으려면 READ_CALL_LOG 권한만 필요로 합니다.

부가 사항들

  • 앱이 Wi-Fi를 스캔하는 데에 필요한 권한 요구사항이 엄격해졌습니다. 정리하면, WifiManager.startScan()ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION 권한을 가지고 있고, CHANGE_WIFI_STATE 권한을 가지고 있어야 합니다. WifiManager.getScanResult()ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION 권한을 가지고 있고, ACCESS_WIFI_STATE 권한을 가지고 있어야 합니다.
  • UTC는 더 이상 GMT와 동의어가 아닙니다.
  • Android 9의 UTF-8 디코더는 이전 버전보다 더욱 엄격하게 Unicode 표준을 준수합니다.
  • /proc/net/xt_qtaguid 폴더에 있는 파일을 직접 읽을 수 없게 됩니다. 이는 이러한 파일이 전혀 없는 기기와의 일관성을 유지하기 위해서 입니다.
  • Android 9부터 Crypto JCA 제공자가 제거되었습니다. SecureRandom.getInstance("SHA1PRNG", "Crypto")를 호출하면 NoSuchProviderException이 발생합니다.

Andorid Pie를 대상으로 하는 앱에 적용되는 지원 사항

  • 포그라운드 서비스를 생성하기 위해서는 FOREGROUND_SERVICE 권한을 요청해야 합니다. 이 권한은 정상 권한이므로 자동으로 권한을 부여합니다. 이 권한 없이 포그라운드 서비스를 시작하면 SecurityException 가 발생합니다.
  • Android 9에서는 Bouncy Castle 제공자가 제공하는 여러 암호화가 지원 중단되고 Conscrypt 제공자가 제공하는 암호화가 대신 사용됩니다. Bouncy Castle 제공자를 요청하는 getInstance() 호출은 NoSuchAlgorithmException 오류를 생성합니다. 이 오류를 해결하려면 getInstance()에서 제공자를 지정하지 마십시오(즉, 기본 구현 요청).
  • Build.SERIAL 가 UNKNOWN 으로 고정됩니다. 단, 하드웨어 일련번호에 엑세스해야 하는 경우에는 READ_PHONE_STATE 권한을 요청한 다음, getSerial() 을 호출해야 합니다.
  • 앱이 더 이상 여러 프로세스에서 단일 WebView 데이터 디렉토리를 공유할 수 없습니다. 앱에 android.webkit 패키지의 WebView, CookieManager 또는 기타 API를 사용하는 프로세스가 2개 이상 있는 경우, 두 번째 프로세스에서 WebView 메서드를 호출하면 앱이 중단됩니다.
  • 시스템은 각 앱의 비공개 데이터 디렉토리 에 대한 앱별 SELinux 샌드박스를 적용합니다. 이제 경로를 통해 다른 앱의 데이터 디렉토리에 직접 엑세스하는 것은 허용되지 않습니다. 앱이 FD 전달을 포함한 IPC 메커니즘을 사용하여 데이터를 계속 공유할 수도 있습니다.
  • 0 영역 (너비나 높이가 0) 이 있는 뷰는 포커스가 불가능합니다. 또한 터치모드에서는 액티비티가 더 이상 초기 포커스를 암시적으로 할당하지 않습니다. 그 대신, 원할 경우 초기 포커스를 명시적으로 요청해야 합니다.

2018. 09. 06. 복귀, 그리고 출발

2018년 8월 9일, 육군훈련소 제 25교육연대 3교육대대 12중대에 입소하고 나서 28일인 오늘(2018년 9월 6일), 제 498기로 교육을 성공적으로 이수하고 수료하였습니다.

가기 전엔 두려움만 있었지만, 막상 다녀와보니 어떤 면에서는 꽤나 즐거운 생활을 보냈다고도 할 수 있었을 것 같습니다. 무엇보다 코딩을 생각하지 않고 한 달을 지냈던 것이 큰 포인트 였던 것 같습니다.

그런 영겁의 한 달을 보내면서 여러 가지 생각을 하게 되었는데, 그 생각과 기대되는 변경사항을 정리하려 합니다.

우선순위 정하기

우선순위를 정하기 전에 리스트를 정리해야 될 것 같습니다.

  • Project. NEW GAME! 서버, 클라이언트(안드로이드) 개발
  • 안드로이드 파이(Pie) 변경사항 파악 및 호환성 체크
  • Kotlin + MVVM 베이스 앱인 PyxisBaseApp 업데이트
  • RxSocialLogin – 야후 로그인, 워드프레스 로그인, 링크드인 로그인, 깃허브 로그인 기능 추가, 코드 리뷰 및 정식 릴리즈 준비
  • ‘함수형 프로그래밍’ 공부

우선순위를 정하면 안드로이드 Pie 가 1번, RxSocialLogin 이 2번, PyxisBaseApp 업데이트가 3번, Project. NEW GAME! 가 4번 일 것 같습니다. 오레오만큼 크나큰 변화는 없는 것으로 파악되지만 백그라운드 권한 제한 및 프라이버시 강화가 포함된 만큼 쉽게 보이지 않는 문제점이 있을 것으로 판단됩니다.

그 다음, RxSocialLogin 은 이미 개발이 다 되어 코드 리뷰 및 정식 릴리즈만 하면 되기 때문에, 빠른 시간 안에 끝날 수 있을거라 판단했고, PyxisBaseApp 의 경우 크나큰 변화는 없겠지만 좀 더 자연스러운 구조를 취하려 합니다.

Project. NEW GAME! 의 경우 현재 서버 개발 40% 를 가리키고 있기 때문에 빠른 시간 안에 서둘러 끝내기 보다는 공부하는 느낌으로 천천히 접근하는 편이 좋다고 생각됩니다.

구텐베르크 에디터 도입

먼저, 워드프레스 5.0 에서 최종적으로 통합될 ‘구텐베르크’ 에디터를 미리 사용하게 되었습니다. 이에 테마 호환성을 고려하지 않으면 안 되는데, Hestia 테마 개발팀인 themeisle 가 다가올 Hestia 2.0 에서 구텐베르크 에디터를 지원할 것이라고 밝혀 그 전까지는 Theme Support for Gutenberg 플러그인을 사용하여 구텐베르크 에디터가 제공할 Wide 환경에 대해 지원할 예정입니다.
그 외 구텐베르크 에디터 관련하여 작고 큰 변경사항이 있을거라 파악되는데, 중요하다고 판단되는 것은 본 섹션에 내용을 추가하는 것으로 갈음하려고 합니다.

그 외 사항들

따로 섹션으로 분리하지 않는 사항 중에는 블로그 글 갱신 갯수 변경 예정이 있습니다. 지금까지는 월 당 하나를 기준으로 지켜왔지만 이제부터는 적어도 두 개 이상을 포스팅하려 합니다. 갯수만 늘리는 것이 아닌 다른 곳에서는 쉽게 볼 수 없는 사항에 대해 정리하고, 제 자신의 지식도 늘리려 합니다.

그리고 가능하다면 안드로이드 라는 주제에 집중된 것이 아닌 다른 분야도 정리할 수 있으면 정리하려 합니다. 예를 들어, Project. NEW GAME! 에서 사용하는 HikariCP 나 Ktor, Exposed 에 대한 자세한 설명 같은 것도 포함될 수 있을 것 같습니다.

앞으로도 누군가에게 도움이 될 수 있는 블로그로 남을 수 있도록 노력하겠습니다.