2010-03-25 4 views
16

stackoverflow posting과 비슷한 작업을하려고합니다. 내가하고 싶은 것은 SD 카드에서 활동이나 서비스의 정의를 읽는 것입니다. 명시적인 사용 권한 문제를 피하기 위해 .apk에서이 활동의 ​​셸 버전을 만들지 만 런타임에 SD 카드에있는 동일한 이름의 활동으로 바꾸려고합니다. 불행히도 DexClassLoader를 사용하여 SD 카드에서 액티비티 클래스 정의를로드 할 수 있지만 원래 클래스 정의는 실행 된 클래스 정의입니다. 새 클래스 정의가 이전 클래스를 대체하도록 지정하거나 패키지에 필요한 활동을 실제로 제공하지 않고 매니페스트 사용 권한 문제를 피하는 방법을 제안 할 수 있습니까? 코드 샘플 : /sdcard/mypath/My.apk에 지정된 com.android.my.path.to.a.loaded.activity을 발사Android, DexClassLoader를 사용하여 활동 또는 서비스를 동적으로 바꾸는 방법

ClassLoader cl = new DexClassLoader("/sdcard/mypath/My.apk", 
      getFilesDir().getAbsolutePath(), 
      null, 
      MainActivity.class.getClassLoader()); 

    try { 
     Class<?> c = cl.loadClass("com.android.my.path.to.a.loaded.activity"); 
     Intent i = new Intent(getBaseContext(), c); 
     startActivity(i); 
    } 
    catch (Exception e) { 

Intead, 그것은 정적으로 프로젝트에로드 활동을 시작합니다.

+0

안드로이드가 자산을 처리하는 방식 때문에이 작업을 수행 할 수 없다는 느낌이 들었습니다. 다른 애플리케이션의 클래스에서 startActivity를 호출 한 경우 애플리케이션의 스레드에서로드하지 않으면 안되므로 Android의 Intents에 대한 위험한 대안 일 수 있습니다. – Tom

답변

13

DexClassLoader를 통한 활동 시작은 APK를 설치하지 않았기 때문에 매우 까다로울 수 있습니다. 따라서 의도를 처리 할 수있는 것이 없습니다.

플랫폼 APK에서 동일한 활동 클래스가 있어야하며 AndroidManifest.xml에 선언해야합니다. 그런 다음 현재 ClassLoader를 원하는 DexClassLoader로 변경해야합니다. 결과적으로 플러그인 APK가 시작됩니다. (참고 : '플랫폼 APK'는 휴대 전화에 이미 설치된 앱을 의미하지만 'APK 플러그인'은 SD 카드에 저장된 apk 파일을 의미합니다.)

플랫폼의 애플리케이션은 다음과 같이 표시되어야합니다.

public static ClassLoader ORIGINAL_LOADER; 
public static ClassLoader CUSTOM_LOADER = null; 

@Override 
public void onCreate() { 
    super.onCreate(); 
    try { 
     Context mBase = new Smith<Context>(this, "mBase").get(); 

     Object mPackageInfo = new Smith<Object>(mBase, "mPackageInfo") 
       .get(); 
     //get Application classLoader 
     Smith<ClassLoader> sClassLoader = new Smith<ClassLoader>(
       mPackageInfo, "mClassLoader"); 
     ClassLoader mClassLoader = sClassLoader.get(); 
     ORIGINAL_LOADER = mClassLoader; 

     MyClassLoader cl = new MyClassLoader(mClassLoader); 
     //chage current classLoader to MyClassLoader 
     sClassLoader.set(cl); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

class MyClassLoader extends ClassLoader { 
    public MyClassLoader(ClassLoader parent) { 
     super(parent); 
    } 

    @Override 
    public Class<?> loadClass(String className) 
      throws ClassNotFoundException { 
     if (CUSTOM_LOADER != null) { 
      try { 
       Class<?> c = CUSTOM_LOADER.loadClass(className); 
       if (c != null) 
        return c; 
      } catch (ClassNotFoundException e) { 
      } 
     } 
     return super.loadClass(className); 
    } 
} 

더 많은 코드의 경우, 나는이 기능을 구현하는 더 우아한 방법을 찾기 위해 안드로이드 소스 코드를 읽고 있어요 https://github.com/Rookery/AndroidDynamicLoader

를 방문 할 수 있습니다. 어떤 생각이라도 있으면 언제든지 저에게 연락하십시오.

+0

당신의 대답은 굉장 +1입니다. 이것은 나의 하루를 만든다. – Krypton

+0

대단한 답변입니다. 링크는 나를 많이 도왔다. – qiuping345

+1

스미스 강습을 여기서 설명하면 더 좋습니다. –

관련 문제