2012-01-10 3 views
4

약간 문제가 있습니다. Android 앱을 개발 중입니다. 다른 응용 프로그램 (패키지)의 클래스를 동적으로로드 할 수 있습니다. 우선, 타사 앱을 "해킹"하고 싶지 않습니다. 내 앱용 플러그인을 만들고 싶습니다. 그래서 내가 무엇을 가지고 있습니까?제네릭 매개 변수가 아닌 메소드 (리플렉션)를 호출하는 방법은 무엇입니까?

2 테스트 응용 프로그램과 두 응용 프로그램에 포함 된 1 개의 라이브러리.

그래서 APP1에 대한 코드 :

package com.ftpsynctest.app1; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.lang.reflect.Type; 
import android.app.Activity; 
import android.content.pm.PackageManager.NameNotFoundException; 
import android.os.Bundle; 
import com.syncoorp.ftpsyncx.commons.SyncFile; 
import dalvik.system.PathClassLoader; 
public class App1Activity extends Activity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     SyncFile f = new SyncFile("bla"); 
     String classname = "com.ftpsynctest.app2.classcall"; 
     String classpath = getApk("com.ftpsynctest.app1") + ":" + getApk("com.ftpsynctest.app2"); 
     PathClassLoader myClassLoader = new dalvik.system.PathClassLoader(classpath, ClassLoader.getSystemClassLoader()); 
     try { 
      Class c = Class.forName(classname, true, myClassLoader); 
      for (Method m : c.getDeclaredMethods()) { 
       System.out.println("Method: " + m.getName()); 
       for (Type t : m.getGenericParameterTypes()) { 
        System.out.println(" - type: " + t.toString()); 
       } 
       m.invoke(c.newInstance(), new Object[] { 
        new com.syncoorp.ftpsyncx.commons.SyncFile("bla") 
       }); 
       break; 
      } 
     } 
     catch (ClassNotFoundException e) {e.printStackTrace();} 
     catch (IllegalArgumentException e) {e.printStackTrace();} 
     catch (IllegalAccessException e) {e.printStackTrace();} 
     catch (InvocationTargetException e) {e.printStackTrace();} 
     catch (InstantiationException e) {e.printStackTrace();} 
    } 

    private String getApk(String packageName) { 
     try { return this.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;} 
     catch (NameNotFoundException e) {e.printStackTrace();} 
     return ""; 
    } 
} 

그래서 내가 방법을 클래스 com.ftpsynctest.app2.classcall를 생성하고 호출 할이 유형 의 매개 변수을 수정 com.syncoorp.ftpsyncx.commons.SyncFile.

내 APP2 코드 :

package com.ftpsynctest.app2; 
import com.syncoorp.ftpsyncx.commons.SyncFile; 
public class classcall { 
    public SyncFile modify(SyncFile file) { 
     file.change_date = 123; 
     return file; 
    } 
} 

처음 설치 APP2는 APP1 할 수있는 클래스를 제공합니다. 그 후 나는 app1을 시작했다.

내 출력 :

01-10 22 : 21 : 48.804 : INFO/(4681) System.out에 : 방법 : (정보/System.out에 : 21 : 48.809
01-10 (22)를 수정 4681) : - 유형 : com.syncoorp.ftpsyncx.commons.SyncFile

이제는보기에 좋았습니다. 발견 된 메소드의 매개 변수 유형은 com.syncoorp.ftpsyncx.commons.SyncFile 이며 제공된 내 용은 동일합니다.

java.lang.IllegalArgumentException: argument type mismatch 
     at java.lang.reflect.Method.invokeNative(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:507) 
     at com.ftpsynctest.app1.App1Activity.onCreate(App1Activity.java:44) 
     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615) 
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667) 
     at android.app.ActivityThread.access$1500(ActivityThread.java:117) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935) 
     at android.os.Handler.dispatchMessage(Handler.java:99) 
     at android.os.Looper.loop(Looper.java:130) 
     at android.app.ActivityThread.main(ActivityThread.java:3691) 
     at java.lang.reflect.Method.invokeNative(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:507) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665) 
     at dalvik.system.NativeStart.main(Native Method) 

그런데 왜 :

는하지만 난 다음과 같은 오류가? 내 출력은 그것이 SyncFile이며 SyncFile을 호출 명령에 넣었다고 알려줍니다. 뭐가 문제 야? app2를 컴파일하면 app1과 다른 SyncFile 클래스를 만들 수 있습니까? 그렇다면 왜? SyncFile 클래스는 두 프로젝트가 공유하는 "커먼즈"라이브러리 내에서 동일한 실제 클래스입니다.

누구나 해결책을 갖고 있습니까?

+0

당신은 작은 문제 부르는위한 아주 큰 생식있다. 문제를 재현 할 수있는 최소 크기로 코드를 줄이십시오. 당신은 실수로 오류를 찾아 낼 것입니다. 그렇지 않다면 여기 다른 사람이 아주 빨리 설명 할 것입니다. –

+1

왜 코드를 줄여야합니까? 이 코드는 내가 필요한 것입니다. 다른 모든 것들이 단지 1 개의 응용 프로그램을 작성하도록 강요 할 것이기 때문에 그것이 될 수있는만큼 축소됩니다. 그러나 그것은 제가 원하는 것이 아닙니다. 내가 안드로이드에 2 개의 다른 앱을 가지고 있다면 그 것들이 작동하는 것이 중요합니다. 내가 제거 할 수있는 유일한 부분은 Exception의 캐치이며 5 – prdatur

답변

0

편집 :이 답변은 잘못되었습니다. 반례는 아래를 참조하십시오.

인수를 Method.invoke()으로 잘못 지정했습니다. 설명서 here을 참조하십시오. 모든 인수의 단일 Object [] 배열을 전달하는 대신 호출 할 인수를 여러 개 전달합니다. 이것이 Object... args 표기법의 의미입니다.이 메서드는 원하는 수의 개체를 허용합니다.

m.invoke(c.newInstance(), new Object[] { 
       new com.syncoorp.ftpsyncx.commons.SyncFile("bla") 
      }); 

을 변경하여 예를 들어

,

m.invoke(c.newInstance(), new com.syncoorp.ftpsyncx.commons.SyncFile("bla")); 

에 문제를 해결해야한다.


반례 :

Refl.java :

package com.drfloob.so; 

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.lang.reflect.Type; 

public class Refl { 
    public static void main(String[] args) { 
     try { 
      Class c = Class.forName("com.drfloob.so.Refl2", true, ClassLoader.getSystemClassLoader()); 
      for (Method m : c.getDeclaredMethods()) { 
       System.out.println("Method: " + m.getName()); 
       for (Type t : m.getGenericParameterTypes()) { 
        System.out.println(" - type: " + t.toString()); 
       } 
       m.invoke(c.newInstance(), "test 1"); 
       m.invoke(c.newInstance(), new Object[] {"test 2"}); 
       break; 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Refl2.java :

package com.drfloob.so; 

public class Refl2 { 
    public Refl2() { 
     System.out.println(Refl2.class); 
    } 

    public void doStuff(String str) { 
     System.out.println(str); 
    } 
} 
+1

은 그렇지 않습니다. 배열을 vararg에 대한 인수로 사용할 수 있습니다. –

+1

정확합니다. 나는 '...'표기법을 오해해야합니다. 나는 비 안드로이드 버전을 코딩하고 어느 쪽이든 작동합니다. 수정 해줘서 고마워. – drfloob

+0

직접적인 인수 패스가 작동하면 오늘 저녁 테스트 해 보겠습니다. – prdatur