2014년 8월 6일 수요일

[Android] 구글 50Mb 용량제한 해결방법

오늘은 구글 50Mb 용량제한 해결방법에대해 포스팅할려고합니다.
사실 구글에 검색하면 많은 자료들이 나오는데요. 네 맞습니다.
영어입니다. 한글도있다구요?  제대로된 설명이 없더라구요.

저도 이번에 50Mb용량제한 생각안하고 어플을 만들다 다 만들고보니 120메가가 훌쩍 넘어버리더라구요.
그래서 찾던중.. 반나절을 고생했네요.

저처럼 고생하는분 없었으면 하는마음에.. 그리고 다음에 또 해야될일 생기면 좀더 편하게 기억을 더듬기 위해서
이렇게 간단히 포스팅하려합니다.

우선 레퍼런스 정보가 담겨있는 주소입니다.
안드로이드 홈페이지이구요. 영어입니다. http://developer.android.com/google/play/expansion-files.html
친절한 어떤분이 한글로 해석해놓은 사이트도 있습니다. 돌아다니다보니 주소를 잊어버렸네요.. 무튼..있습니다(허허.)
-- 추가 --
해석해놓은 페이지 찾아서 다시 적습니다 ㅎ  http://gameforfun.tistory.com/103


1. 확장파일?
우선 확장파일 만드는 방법을 간단히 설명드리겠습니다.
일반적으로 어플리케이션은 이미지파일이나 음악, 동영상 등등 파일들을 res나 혹은 assets에 많이 관리들 하시는데요.
assets가 대부분이시겠죠. 소규모프로그램은 상관없지만, 용량이 커지다보면 50Mb넘어버리기는 일수입니다.
그래서 기본적인 파일들은 apk로 만들고, 리소스가 들어있는 assets폴더 혹은 일부를 (일부를 떼실때에는 이미지든, 동영상이든, 사운드든 아무것이나 상관없습니다) apk에서 제외해서 따로 압축합니다.(zip) 그래서 어플 등록할때 apk와 함께 zip을 업로드하는 것이지요.   이해되시나요..?

확장파일의 저장경로는 
Android\obb\ PackageName\main.PackageVersion.PackageName.obb  입니다.
PackageVersion에는 버전코드 1.0.0 혹은 4.0.3  이런거 있죠. 제일 앞자리만 들어갑니다 ( 앞에서 예로든 버전으로는 1 혹은 4 )
PackageVersion에는 버전네임이 아닌 버전 코드가 들어갑니다. (마켓이 올릴때 올려야하는 그 1.0.0말고 1,2 ,100 등의 코드

그래서 예를들어 com.example.test 라는 패키지의 ver 1.0.0 어플의 저장경로는
Android\obb\com.example.test\main.1.com.example.test.obb  입니다.
굳이 외우지 않으셔도 됩니다. 소스에서 다 처리해줄거니까요.

보통 일반적으로 Assets폴더에서 리소스를 참조할경우 그냥 AssetsGet 하면 되지만, 이제부턴 불러오는 위치를 저기로 바꿔야합니다. (이미지가 다른곳에 있는거니까요)

확장파일의 이름은   아무거나.zip로 해서 올리면 구글에서 알아서 위의 이름이 맞게 바꿔서 서버에 저장됩니다.
파일명도 신경쓰지 않으셔도 됩니다.

(13.10.14 추가)
- 화장파일 압출하실때에는 압축옵션중에 '압축 안함' 이라고 있습니다. 반드시 이걸로 압축해야합니다~!    오랜만에 새로 할려고하니 이부분을 잊고 지나가서 한참 삽질했네요 ㅜ


50Mb가 넘어버렸을때에는 구글이 아닌 T스토어나 기타 다른마켓으로 가시면 손쉽게 해결됩니다. ( 구글보다 용량제한이 덜하거든요.. ) 굳이 구글에 올리시겠다! 그럼 밑으로 쭉 읽으시면 됩니다.

계속 하겠습니다.


2. 확장파일 만들 환경 세팅하기
1) 우선 SDK매니저를 실행하셔서 라이브러리 2개를 설치합니다

Extras - Google Play Licensing Library , Google Play APK Expansion Library 2개를 설치해줍니다.

설치하게되면
sdk/extras/google 경로에
play_apk_expansion 폴더와 play_licensing 폴더가 생성됩니다.

그러면 이제 이클립스로가서
play_apk_expansion 폴더안에있는 downloader_library 하고 zip_file 2개를 Import 해줍니다. 그리고
play_licensing 폴더안에있는 library를 Import해줍니다.
(자바프로젝트로 임포트하지말고 안드로이드 프로젝트로 임포트해주세요)

2) downloader_library 프로젝트에서 오른쪽마우스 - Properties - Android - Library보시면 market_licensing 를 참조하고 있을겁니다. 그러시다면 깔끔하게 Remove눌러서 삭제해줍니다. ( 이게 왜그런지 모르겠는데 최신버전오면서 바뀐건지.. 정확한 이유는 모르겠네요 )

그리고 Add를 눌러서 아까 Import한 Library를 참조합니다.

3) 그런다음, 적용할려는 프로젝트에  오른쪽마우스 - Properties - Java Build Path로 가셔서 Add JARs..를 눌러줍니다.
downloader_library , zip_file 2개를 추가하는데
경로 - bin에 가보면 jar파일 있습니다. 그거2개 추가해줍니다.

그리고 오른쪽에 Order and Export 가셔서 방금 추가한 2개를 체크 해줍니다.
이제 기본적인 세팅은 끝났습니다. 이제 코딩을 시작해볼까요.

4) 확장파일에서 이미지 가져오기

우선 앞에서 설명했었던, 확장파일의 경로에서 이미지를 불러오는 방법입니다.

우선 파일을 가져올 함수부터 만들겠습니다. getAssetFileDescriptor() 함수입니다.
01.public AssetFileDescriptor getAssetFileDescriptor(String filePath)
02.{
03.PackageManager manager = this.getPackageManager();
04.PackageInfo info;
05. 
06.try
07.{
08.info = manager.getPackageInfo( this.getPackageName(), 0);
09.}
10.catch (NameNotFoundException e)
11.{
12.// TODO Auto-generated catch block
13.e.printStackTrace();
14.returnnull );
15.}
16. 
17.String thePackageName = this.getPackageName();
18.int thePackageVer = info.versionCode;
19. 
20.String zipFilePath = "/mnt/sdcard/Android/obb/" + thePackageName + "/main." + thePackageVer + "."+ thePackageName + ".obb";
21. 
22.ZipResourceFile expansionFile = null;
23.AssetFileDescriptor afd = null;
24. 
25.try
26.{  
27.expansionFile = new ZipResourceFile(zipFilePath);  
28.afd = expansionFile.getAssetFileDescriptor(filePath);  
29.}
30.catch (IOException e)
31.{  
32.e.printStackTrace();
33.}
34.return afd; 
35.}   
그리고 이미지를 불러와야 하는 부분에서 이런식으로 getAssetFileDescriptor함수를 호출하면 됩니다.
01.AssetFileDescriptor readFile = getAssetFileDescriptor("이미지 파일 경로/이름");
02. 
03.Bitmap image;       
04.if( readFile != null )
05.{
06.try
07.{
08.Drawable d = Drawable.createFromStream(readFile.createInputStream(), null);
09.image = ((BitmapDrawable)d).getBitmap();
10.}
11.catch (IOException e)
12.{
13.// TODO Auto-generated catch block
14.e.printStackTrace();
15.}
16.}

이러면 불러온 이지지가 Bitmap에 들어가있습니다.

음.. 끝났나요 벌써?

추가로 설정해야하는 부분이 있습니다.
구글에서는 일반적으로 apk를 다운받을때, 확장파일이 있으면 자동으로 확장파일까지 다운받습니다.
하지만 간혹, 때에따라서 확장파일받는중 오류가 발생하기도 합니다. 그럴때에는 직접 URL에 연결해서 그 파일을 받아야하는데요.

그 처리를 해보겠습니다.


5) 확장파일 다운실패했을경우의 처리
우선 Manifest에 추가해야할 내용이 있습니다.

01.<uses-permission android:name="com.android.vending.CHECK_LICENSE">
02.<uses-permission android:name="android.permission.INTERNET">
03.<uses-permission android:name="android.permission.WAKE_LOCK">
04.<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
05.<uses-permission android:name="android.permission.ACCESS_WIFI_STATE">
06.<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
07. 
08.<service android:name=".ExpansionFileDownloaderService" android:label="@string/app_name"><span style="font-size: 11pt;">
09.<receiver android:name=".ExpansionFileAlarmReceiver" android:label="@string/app_name"><span style="font-size: 11pt;">
10.</span></receiver></span></service></uses-permission></uses-permission></uses-permission></uses-permission></uses-permission></uses-permission>
다음으로 제일처음 시작하는 Activty Oncreate에서 다운받았는지에 대한 확인을 하고 다운로드를 처리합니다.
01.// Check whether the file have been downloaded.
02.String mainFileName = Helpers.getExpansionAPKFileName(thistrue1);
03.boolean fileExists = Helpers.doesFileExist(this, mainFileName, 파일용량L , false);
04.if (!fileExists) {
05.Intent launcher = getIntent();
06.Intent fromNotification = new Intent(this, getClass());
07.fromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
08.fromNotification.setAction(launcher.getAction());
09.if (launcher.getCategories() != null) {
10.for (String cat : launcher.getCategories()) {
11.fromNotification.addCategory(cat);
12.}
13.}
14.PendingIntent pendingIntent = PendingIntent.getActivity(
15.this0, fromNotification, PendingIntent.FLAG_UPDATE_CURRENT);
16.try {
17.// Start the download
18.int result = DownloaderClientMarshaller.startDownloadServiceIfRequired(
19.this, pendingIntent, ExpansionFileDownloaderService.class);
20.if (DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED != result) {
21.// implement Downloading UI.
22.return;
23.}
24.catch (NameNotFoundException e) {
25.Log.e("apk-expansion-files""NameNotFoundException occurred. " + e.getMessage(), e);
26.}
27.}
28.// expansion file is available. start your application.

주의할점은 위에 파일용량L이 있는데, 저것은 확장파일 zip파일의 등록정보 봤을때 뜨는 바이트 용량크기입니다.
이 크기가 다르면 다운로드 안되니 반드시 정확하게 입력해주세요.



6) 끝났냐구요? 마지막입니다.

클래스를 만들어주세요.
01.// Extends com.google.android.vending.expansion.downloader.impl.DownloaderService class and override three methods.
02.public class ExpansionFileDownloaderService extends DownloaderService {
03.// the Base64-encoded RSA public key for your publisher account
04.private static final String PUBLIC_KEY = "{YOU_PUBLIC_KEY}";
05.// Generate 20 random bytes, and put them here.
06.private static final byte[] SALT = new byte[] {};
07.@Override public String getPublicKey() {
08.return PUBLIC_KEY;
09.}
10.@Override public byte[] getSALT() {
11.return SALT;
12.}
13.@Override public String getAlarmReceiverClassName() {
14.return ExpansionFileAlarmReceiver.class.getName();
15.}
16.}
 

01.public class ExpansionFileAlarmReceiver extends BroadcastReceiver {
02.@Override public void onReceive(Context context, Intent intent) {
03.try {
04.DownloaderClientMarshaller.startDownloadServiceIfRequired(
05.context, intent, ExpansionFileDownloaderService.class);
06.catch (NameNotFoundException e) {
07.Log.e("apk-expansion-files""NameNotFoundException occurred. " + e.getMessage(), e);
08.}
09.}
10.}

2개입니다.



이상입니다. 이미지가 안들어가있어서 보기 힘드실텐데. 한줄한줄 읽으면서 천천히 따라하면 충분히 모두 다 해내실겁니다^^
질문은 댓글로 주세요. 

마켓이 업로드할때는 apk올리고 확장파일 따로 올리는거 아시죠^^?
모두들 즐프 하세요~

댓글 없음:

댓글 쓰기