Android - 라이브러리 프로젝트에 난독화 적용하기 with ProGuard

라이브러리를 만들다보면 코드를 난독화시켜야 하는 이슈가 발생합니다. 예를 들면 보안상의 이유라든지 아니면 소스 유출을 방지하기 위한 목적으로 말이죠. 오늘 글에서는 안드로이드 라이브러리(jar)에 ProGuard를 적용하는 방법을 알아보도록 하겠습니다.

ProGurad 정의와 개념

안드로이드 라이브러리를 난독화하기 전에 코드를 난독화 시킬 때 사용할 ProGuard에 대해 설명하면, ProGuard는 JVM 기반 애플리케이션의 성능과 보안을 향상시키기 위해 사용하는 오픈 소스 도구입니다. 다시 말해 ProGuard를 사용하면 손쉽게 코드를 축소화, 최적화 및 난독화 할 수 있습니다. ProGuard가 지원하는 기능은 크게 3가지 입니다.

 

 1. 축소화(Shrinking): 사용하지 않는 코드와 리소스를 제거하여 애플리케이션의 크기를 최소화합니다. 이를 통해 실행되는 코드의 크기를 줄일 수 있고, 코드를 분할해 필요에 따라 동적 로딩 할 수 있습니다.

 

 2. 최적화(Optimization): 코드와 리소스를 최적화시켜 실행 시간을 단축시킵니다. 불필요한 메서드 호출을 제거하고, 상수 폴딩, 인라인 확장 등의 최적화 기법을 적용 할 수 있습니다.

 

 3. 난독화(Obfuscation): 코드를 난독화하여 해킹이나 리버스엔지니어링을 어렵게 만듭니다. 클래스, 메서드, 변수 이름을 난독화하여 코드를 이해하기 어렵게 만들고 중요한 비지니스와 알고리즘을 보호 할 수 있습니다.

 

 안드로이드 스튜디오를 통해 만든 최신의 안드로이드 프로젝트는 ProGuard가 기본 옵션으로 적용되고, ProGuard가 제공하는 기능들은 필요에 따라 옵션을 선택해 적용 할 수 있습니다.

안드로이드 프로젝트 라이브러리(jar)로 만들기

먼저 난독화를 적용 할 라이브러리를 만드는 방법을 알아보겠습니다. jar 파일을 만드는 방법은 다음과 같습니다. 아래와 같이 build.gradle 파일에 jar 스크립트를 추가해주세요.

task deleteJar(type: Delete) {
    delete 'build/release/sample-lib.jar'
}

task exportJar(type: Copy) {
    from('build/intermediates/aar_main_jar/release/')
    into('build/release/')
    include('classes.jar')
    rename('classes.jar', 'sample-lib.jar')
}

exportJar.dependsOn(deleteJar, build)

 안드로이드 프로젝트는 build task를 가지고 있고, build task가 진행되면 build 하위 폴더 intermediates에 jar 파일이 만들어지기 때문에 우리는 이 jar 파일을 가져다 사용하면 됩니다.

ProGuard로 라이브러리에 난독화 적용하기

앞서 안드로이드 프로젝트를 라이브러리화 시켰다면, 이제는 ProGuard를 사용해 난독화를 적용할 순서입니다. 이번에도 아래와 같이 build.gradle 파일에 스크립트를 추가해주세요.

task deleteProguard(type: Delete) {
    delete 'build/release/compress'
}

task applyProguard(type: proguard.gradle.ProGuardTask) {
    configuration file('proguard-manual.pro')

    injars('build/release/sample-lib.jar')
    outjars('build/release/compress')
}

applyProguard.dependsOn(exportJar, deleteProguard)

 ProGuard를 사용해 적용할 기능은 proguard-manual.pro 파일에 설정 내용을 정의하면 됩니다. 설정에 대한 구체적인 내용은 링크를 통해 확인해주세요.

build 설정 파일 전체

build.gradle module

plugins {
    id 'com.android.library'
}

android {
    namespace 'com.library.sample'
    compileSdk 31

    defaultConfig {
        minSdk 24
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
//            consumerProguardFiles 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

task deleteJar(type: Delete) {
    delete 'build/release/sample-lib.jar'
}

task exportJar(type: Copy) {
    from('build/intermediates/aar_main_jar/release/')
    into('build/release/')
    include('classes.jar')
    rename('classes.jar', 'sample-lib.jar')
}

task deleteProguardJar(type: Delete) {
    delete 'build/release/compress'
}

task applyProguard(type: proguard.gradle.ProGuardTask) {
    configuration file('proguard-manual.pro')

    injars('build/release/sample-lib.jar')
    outjars('build/release/compress')
}

exportJar.dependsOn(deleteJar, build)

applyProguard.dependsOn(deleteProguardJar, exportJar)

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

build.gradle project

plugins {
    id 'com.android.application' version '8.0.1' apply false
    id 'com.android.library' version '8.0.1' apply false
}
반응형

댓글

Designed by JB FACTORY