이 포스팅은 아래 링크를 기반으로 작성되었습니다.
앱을 설치하지 않고 다운로드 받은 소스를 곧바로 실행하기
결론 : API level 3부터 지원하는 DexClassLoader를 이용합니다.
들어가며
Dev apps direct 라는 앱이 있습니다.
https://play.google.com/store/apps/details?id=com.inappsquared.devappsdirect
이 앱은 단언컨대 안드로이드와 깃허브를 쓰는 개발자들의 필수품입니다.
안드로이드 오픈소스 라이브러리의 샘플 소스가 실행가능한 예제로 올라와 있는데, 최근버전 업데이트에서는 로메인 기(안드로이드 플랫폼 개발자!)가 올린 소스도 샘플로 올라와 있습니다.
물론 직접 깃허브에서 다운로드 받아 빌드하여 결과를 확인해도 됩니다. 그러나 이 앱을 활용하면 그 과정 없이 폰에서 곧바로 새로나온 오픈소스를 돌려볼 수 있습니다. (이 앱에서 제공하는 것만 된다는 단점이 있습니다만)
앱 내에는 깃허브에서 엄선한 오픈소스 라이브러리, 예를 들면 사이드 바, 텍스트뷰에 스포트라이트 광원효과, 아이폰같은 효과를 내는 팝업 등등의 쓸모있는 라이브러리가 가득합니다. 즉 사장님이나 갑의 손에 이 앱이 들어가는 일을 막아야 하기 때문에 개발자 여러분께서는 몰래몰래 보셔야 합니다.
어떻게 구현할까?
궁금증이 생깁니다.
이 앱은 (1) 별도의 설치과정없이 (2) 웹에서 (깃허브에서) 다운로드 받은 소스를 (3) 곧바로 실행합니다.
즉, 단순히 리소스 다운로드가 아니고 새로운 앱을 다운로드 받는 것입니다. 이런 것이 가능할까요?
가능합니다. 처음 언급한 Stack overflow 링크 내용을 보면 :
- android develop가 질문:
그냥 궁금증 때문에 물어보는 건데, Dev apps direct 같은 앱을 보면 인스톨도 하지 않고 곧바로 앱을 실행시킵니다. 이게 가능한가요?
소스를 다운받아서 스스로의 소스에 머지(Merge)하는 건가요? 아니면 어떤 플러그인 같은 건가요? apk를 다운로드 받아서 그걸 실행하는 건가요?
이걸 어떻게 구현하는지 알게되면 앱의 플러그인 같은 걸 구현하는데 유용할 것 같습니다.
- Neiti01 이 답변:
가능합니다. Class loader를 이용하면 됩니다. (이 경우에는 PathClassLoader를 이용하면 되겠군요)
아래 소스를 참고하세요.
https://github.com/Rookery/AndroidDynamicLoader
- android developer가 자답:
제가 직접 devAppsDirect에 질문을 했는데, 이런 답변을 받았습니다.
"DevAppsDirect에 쓰인 기술은 inAppSquared라는 기술입니다. (www.inAppSquared.com) 넛셀(nutshell)에서는 안드로이드 앱을 플러그인으로 만들 수 있습니다. 이것은 공개된 안드로이드 API만을 이용하고, 어떤 트릭이나 해킹을 이용하는 것이 아닙니다.
저는 Xamarin이나 Titanium 플랫폼을 만드는 방식과 동일하게 이 기술을 만들었습니다. inAppSquared 에서 다른 점은, 이용하는 API가 안드로이드 API라는 점이고, 안드로이드앱이 inAppSquared로 포팅되면 그 다음에는 인스톨 없이 실행될 수 있다는 점입니다.
이 기술의 활용방안은 무궁무진합니다. 말씀하신대로 플러그인이나 확장에 이용할 수도 있고, 앱 설치, 광고, 구독서비스, A/B 테스트 (두 개의 버전을 비교해 가며 이용자의 반응을 확인하는 테스트. 마켓에 하나의 버전을 올릴 수 밖에 없는 현재 구조에서는 불가능) 에 이용할 수 있습니다.
즉 inAppsSquared 라는 기술을 이용하는 방법, Class loader를 이용하는 방법 두 가지가 있다고 볼 수 있겠습니다. 전자는 상업용으로 구현된 기술이고 내부구조가 공개되어있지 않고, 후자는 이 API를 이용하여 직접 개발해야한다는 천지차이의 차이점이 있습니다만.....
Rookery/AndroidDynamicLoader 분 석
ActivityLoader.java파일이 핵심입니다.
먼저 가지고 있는 apk 파일로 리스트를 만들고,
protected void onCreate(Bundle savedInstanceState) { ... AssetManager asset = getAssets(); for (String s : asset.list("apks")) { addItem(s, "apks/" + s); } ...
아이템 클릭 시 로딩합니다.
protected void onListItemClick(ListView l, View v, int position, long id) { ... File dex = getDir("dex", Context.MODE_PRIVATE); dex.mkdir(); File f = new File(dex, title); InputStream fis = getAssets().open(path); FileOutputStream fos = new FileOutputStream(f); byte[] buffer = new byte[0xFF]; int len; while ((len = fis.read(buffer)) > 0) { fos.write(buffer, 0, len); } fis.close(); fos.close(); File fo = getDir("outdex", Context.MODE_PRIVATE); fo.mkdir(); // 이 부분에서 클래스 로드 DexClassLoader dcl = new DexClassLoader(f.getAbsolutePath(), fo.getAbsolutePath(), null, MyApplication.ORIGINAL_LOADER.getParent()); MyApplication.CUSTOM_LOADER = dcl; Toast.makeText(this, title + " loaded, try launch again", Toast.LENGTH_SHORT).show(); ...
어떻게 활용할까?
다양합니다.
(1) 플러그인이나 추가리소스를 다운로드 받아 쓸 수 있습니다. 일부 게임 앱에서 리소스를 다운로드 받는 것과 유사한 동작이라 생각하시면 되겠습니다.
(2) A/B 테스트. 버전 A와 버전 B, 두 가지 버전의 앱을 마켓에 출시하여 이용자의 반응을 살필 수 있습니다. 물론 구글 마켓에 버전 A, 티스토어에 버전 B를 출시하여 반응의 차이를 확인할 수도 있겠지만...... 이 방식이 더 세련되어 보입니다.
더 자세한 내용은 아래 링크를 참조하시기 바랍니다.
http://developer.android.com/reference/dalvik/system/DexClassLoader.html
'Android' 카테고리의 다른 글
이클립스의 유용한 플러그인 (3) | 2014.05.24 |
---|---|
eclipse invalid project description 발생 시 (0) | 2014.05.20 |
android:contentDescription 은 어디에 써먹을 수 있을까 ( Dump View Hierarchy 활용) (0) | 2014.03.09 |
이클립스가 뻗었을 때 대처법 (0) | 2014.02.27 |
안드로이드 메모리 릭 체크 - Eclipse Memory Analyzer (0) | 2014.02.26 |