[Android] Expansion file 이용하기 - 1
구글에서 APK 제한을 두고 있습니다.
앱에 100MB 이상의 메모리가 필요한 경우 확장 파일을 사용해 APK 애셋을 더 저장할 수 있습니다. 앱당 확장 파일 2개를 저장할 수 있으며 각 확장 파일의 크기는 최대 2GB까지 가능합니다.
APK 파일의 최대 파일 크기는 APK에서 지원하는 Android 버전에 따라 다릅니다.
- 100MB - Android 2.3 이상을 대상으로 하는 APK(API 레벨 9~10 및 14 이상)
- 50MB - Android 2.2 이하를 대상으로 하는 APK(API 레벨 8 이하)
도움말: 사용자가 100MB APK를 설치하려면 Play 스토어 버전 5.2 이상을 실행해야 합니다.
확장 파일은 추가 비용 없이 호스팅됩니다. 가능한 경우 Google Play는 앱을 설치하거나 업데이트할 때 확장 파일을 다운로드합니다. 앱에서 확장 파일을 다운로드해야 하는 경우도 있습니다.
확장 파일이 100MB보다 큰 경우 사용자에게 Wi-Fi를 사용하여 앱을 다운로드하라는 경고 문구가 표시됩니다.
출처 : https://support.google.com/googleplay/android-developer/answer/2481797?hl=ko
만약 내 앱이 100MB가 넘을 경우, Google Play Console에서 APK 등록 할때 에러를 토해냅니다.
해결할 수 있는 방법 중에 하나가 Expansion File을 이용 하는 것 입니다.
한 파일당 최대 2GB 이며, 파일 2개 까지 이니 4GB 까지 확장 파일을 등록 시킬 수 있는 것입니다.
이건 따로 서버를 둘 필요도 없고, 구글이 알아서 저장했다가,
유저가 앱 설치시 자동으로 다운로드 되도록 하는 기능 입니다.
서론이 길었네요. 그럼 어떻게 이용하는지 바로 해보겠습니다.
여러 자료 들이 많지만, 이해하기가 어려워 그냥 제 나름대로 간편하게 할 수 있을 만큼 만들어 보았습니다.
## 예제 흐름
확장파일에 저장되어 있는 이미지를 불러와서 ImageView에 뿌르는 예제 입니다.
그럼 하나하나 진행 해보겠습니다.
1. 먼저, ImageView 하나를 가진 새로운 프로젝트를 만드세요.
(혹시, 새로운 안드로이드 프로젝트를 만드는데 어려움이 있으시분들은 댓글 달아주세요. ㅎ)
참고로, 전 'com.example.gorchg.expansiontest' 패키지명으로 풀사이즈 ImageView하나 추가해놓았습니다.
2. 새로운 프로젝트에 이제 Expansion File을 사용해야할 모듈을 추가 해야 하는데요.
이 모듈은 android-sdk에 포함되어 있는데요. Eclipse 소스라 그대로 모듈 추가가 되지 않습니다.
그래서, 별도로 모듈을 하나 만들고 그 모듈에 소스를 붙여 넣는 형태로 해야 합니다.
그럼 추가할 모듈은 아래 사진과 같은 위치에 있습니다.
## 추가할 모듈
android-sdk/extras/google/market_apk_expansion/downloader_library : 확장 파일을 다운 받게 도와주는 라이브러리
android-sdk/extras/google/market_apk_expansion/zip_file: 확장 파일이 압축 파일입니다. 이 압축파일을 제어하기 위한 라이브러리
android-sdk/extras/google/play_licensing/library: downloader_library에서 이용하는 라이브러리로 다운로드 관련 라이센스 제어 라이브러리
이 3가지 모듈을 추가 하면 됩니다. 추가 하는 방법 은 아래와 같습니다.
설명은 downloader_library만 하겠습니다. 나머지 모듈도 같은 형태로 하면 되고, 추가한 소스는 마지막에 공유해드리겠습니다.
File -> New -> New Module... 을 선택 합니다.
Android Library를 선택 하고 Next 버튼을 누릅니다.
여기서 Module name(원하시는 대로 쓰시면 됩니다. ) 을 쓰신 후, 패키지명은 복사할 소스에 패키지명으로 해주세요.
아래는 downloader-library의 AndroidManifest.xml에 있는 패키지 명입니다.
이렇게 만들어진 모듈에 소스를 복사하면 됩니다. 그럼 아래와 같은 형태가 되는데요.
downloader-library는 licensing 라이브러리를 사용하므로, build.gradle에 'compile project(':licensing')'을 추가 해주세요.
마지막으로 만드신 프로젝트 'downloader-library'와 'zip_file'을 추가하면 모듈 추가는 완료 됩니다.
이제 모듈 추가를 했으니 확장 파일을 이용해볼까요?
확장 파일은 앱 설치시 아래와 같은 경로에 자동으로 다운 받아 집니다.
Android/obb/앱 패키지명/main.앱 패키지 버전.앱 패키지명.obb
versionCode 1
applicationid com.example.gorchg.expansiontest
위와 같이 build.gradle이 정의 되어 있을 경우 아래와 같이 저장이 됩니다.
Android/obb/com.example.gorchg.expansiontest/main.1.com.example.gorchg.expansiontest.obb
그럼 확장 파일을 이용할려면 확장 파일을 google play console에 등록 해서 앱을 받아야지만 이용할 수 있을까요??
아닙니다. 테스트를 하는데 매번 그러면 번거롭죠.
그래서 아래와 같이 해보세요.
확장 파일로 만들고 싶은 모든 파일을 하나의 압축 파일로 만듭니다. (다중 폴더, 다중 파일 상관 없습니다.)
전, 이미지 3개를 하나의 압축 파일로 만들었습니다.
테스트를 하실 때는 압축을 없앤 형태로 압축 파일을 만드세요.
아래는 반디집으로 압축한 형태 입니다.
'압축 하지 않음'을 선택 하였습니다.
이렇게 만들어진 압축 파일의 파일명을 강제로 바꿔주세요.
저 같은 경우 main.1.com.example.gorchg.expansiontest.obb 이렇게 되겠죠.
이 파일을 테스트할 폰 외장 메모리에 복사합니다. 복사할 위치는 아래와 같습니다.
Android/obb/앱 패키지명/
저 같은 경우는 이렇게 되겠네요.
Android/obb/com.example.gorchg.expansiontest/
그럼 테스트할 확장 파일 준비도 끝났습니다.
이제 앱에 적용 시켜 보겠습니다.
## AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gorchg.expansiontest">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
## activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.gorchg.expansiontest.MainActivity">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
## MainActivity.java
package com.example.gorchg.expansiontest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import com.android.vending.expansion.zipfile.ZipResourceFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.img);
getAssetFileDescriptor();
}
public void getAssetFileDescriptor(){
PackageManager pkmanager = this.getPackageManager();
PackageInfo info;
try{
info = pkmanager.getPackageInfo(this.getPackageName(), 0);
}catch(PackageManager.NameNotFoundException e){
e.printStackTrace();
return;
}
String thePackageName = this.getPackageName();
int thePackageVer = info.versionCode;
File root = Environment.getExternalStorageDirectory();
String zipFilePath = root.toString() + "/Android/obb/"+thePackageName+"/main."+
thePackageVer+"."+thePackageName+".obb";
try{
ZipResourceFile expansionFile = new ZipResourceFile(zipFilePath);
InputStream is = expansionFile.getInputStream("picture_1.JPG");
this.mImageView.setImageDrawable(Drawable.createFromStream(is, null));
}catch(IOException e){
e.printStackTrace();
}
}
}
## 결과 화면
여기 까지 소스 파일을 올립니다.
다음 포스트에서 Google play console에 확장 파일을 저장 하고,
설치한 앱에서 출력해보도록 하겠습니다.
참고하세요.