[android] APK Expansion 사용하기

apk가 100MB다.

구글 플레이 스토어에 올리려고보니

screenshot_2014-12-01_PM 9.03.57

이런게 뜬다. 와 식겁했다.

 

 

이리저리 검색해보니 APK 확장 파일(APK Expansion Files) 라는 기능을 사용하면 되나 보다.

설명은 http://developer.android.com/google/play/expansion-files.html

 

 

 

어려운건 예제를 만들어야 이해가 쉬운 법!

 

 

 1. 예제 프로그램 작성

asset을 사용하는 예제 프로그램을 만든다.

screenshot_2014-12-01_PM 9.15.26

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="kr.mint.testapkexpansion.MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click!" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:src="@drawable/img_002" />

</LinearLayout>

 

public class MainActivity extends Activity
{
  private ImageView _imageview;
  
  
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    _imageview = (ImageView) findViewById(R.id.imageView1);
    
    findViewById(R.id.button1).setOnClickListener(new OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        change();
      }
    });
  }
  
  
  private void change()
  {
    try
    {
      InputStream ims = getAssets().open("img_001.png");
      Drawable d = Drawable.createFromStream(ims, null);
      _imageview.setImageDrawable(d);
    }
    catch (IOException ex)
    {
      return;
    }
  }
}

 

 

 

device-2014-12-01-211745

 

 

device-2014-12-01-211754

 

클릭하면 가운데의 이미지가 img_002에서 img_001로 바뀐다.

 

 

screenshot_2014-12-01_PM 8.56.30

일단 마켓의 알파에다 업로드를 한다.

(최초 업로드에서는  확장파일을 올릴 수 없다)

 

알파테스트 등록하는건 알아서 하는걸로…

 

 

 

2. 라이브러리 다운로드

SDK 매니저에서

screenshot_2014-12-01_PM 9.20.20

Google Play APK Expansion Library, Google Play Licensing Library 를 다운로드 한다.

 

그런 다음 아래의 프로젝트를 import 한다.

sdk ▸ extras ▸ google ▸ play_apk_expansion ▸ downloader_library

sdk ▸ extras ▸ google ▸ play_apk_expansion ▸ zip_file

sdk ▸ extras ▸ google ▸ play_licensing ▸ library

 

혹시나 downloader_library에서 오류가 나면 play_licensing 을 다시 등록해주면 된다.

screenshot_2014-12-01_PM 9.26.39

 

 

아마도 자동으로 혹은 컴파일을 해주면 jar 파일이 생긴다.

sdk ▸ extras ▸ google ▸ play_apk_expansion ▸ downloader_library ▸ bin ▸ downloader_library.jar

sdk ▸ extras ▸ google ▸ play_apk_expansion ▸ zip_file ▸ bin ▸ zip_file.jar

 

요 두 파일을 아까의 저 프로젝트의 libs에 복사한다.

screenshot_2014-12-01_PM 9.29.56

 

 

3. asset 에서 이미지 불러오는 부분 수정

asset을 불러오는 방법이 바뀌어야 하니까 코드를 수정한다.

 

private void change()
{
  try
  {
//      InputStream ims = getAssets().open("img_001.png");
    ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(getApplicationContext(), 2, 0);
    InputStream ims = expansionFile.getInputStream("img_001.png");
    
    Drawable d = Drawable.createFromStream(ims, null);
    _imageview.setImageDrawable(d);
  }
  catch (IOException ex)
  {
    return;
  }
}

소스 가져온 곳 : Using the APK Expansion Zip Library

 

혹은 이 렇게 사용해도 된다.

private void change()
{
  try
  {
    File path = new File(Environment.getExternalStorageDirectory() + "/Android/obb/" + getPackageName());
    
    if (path.exists())
    {
      File filePath = new File(path + File.separator + "main." + 6 + "." + getPackageName() + ".obb");
      ZipResourceFile zipfile = new ZipResourceFile(filePath.toString());
      Drawable d = Drawable.createFromStream(zipfile.getInputStream("img_001.png"), null);
      _imageview.setImageDrawable(d);
    }
  }
  catch (Exception e)
  {
    e.printStackTrace();
  }
}

 

 

 

java.lang.NullPointerException
	at kr.mint.testapkexpansion.MainActivity.change(MainActivity.java:46)
	at kr.mint.testapkexpansion.MainActivity.access$0(MainActivity.java:40)
	at kr.mint.testapkexpansion.MainActivity$1.onClick(MainActivity.java:34)
	at android.view.View.performClick(View.java:4438)
	at android.view.View$PerformClick.run(View.java:18422)
	at android.os.Handler.handleCallback(Handler.java:733)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:136)
	at android.app.ActivityThread.main(ActivityThread.java:5017)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:515)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
	at dalvik.system.NativeStart.main(Native Method)

이 상태로 이클립스에서 실행하면 당연히 이런 오류가 난다.

 

 

screenshot_2014-12-01_PM 9.51.47

assets에서 img_001을 제거한다.

 

 

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

read 퍼미션도 필요하다.

 

screenshot_2014-12-01_PM 9.47.20

menifest의 버전을 하나 올리고 다시 apk를 만든다.

 

 

screenshot_2014-12-01_PM 9.53.30

그리고 img_001 파일은 압축파일로 만든다.

파일 이름은 아무렇게나 해도 괜찮다.

 

 

마켓에 가서 업로드를 한다.

screenshot_2014-12-01_PM 9.54.59

apk를 업로드하면 이런 창이 뜨고,   “확장 파일 없음” 을 선택해서 img_001.png.zip을 업로드하면

 

screenshot_2014-12-01_PM 9.55.20

이렇게 바뀐다.

 

앱을 출시하고, 알파테스터가 받아서 확인해보면 된다.

 

 

 

4. 마켓에서 다운받은 후

몇 번의 실패 후 드디어 성공했다 ㅠㅠ

 

screenshot_2014-12-02_PM 4.45.21

일단 마켓에서 다운을 받으면 저렇게 파일이 자동으로 생긴다.

아마 마켓에서 다운로드 하는 중간에 같이 받아지는 것 같다.

 

 

 

5. 팁

앱을 지우면 저 obb 파일도 같이 지워지기 때문에 테스트하기가 너무 골치아팠다.

혹시나 다른 앱에서 저 파일을 읽을 수 있는지를 해봤는데, 다행히 잘 된다 ㅎ