3

プラグインビューを許可するホームオートメーションアプリを作成しています。

概念実証として次のコードがあります。

プラグインのインターフェースを使用してAndroidライブラリプロジェクトを作成しました。

package com.strutton.android.UIPlugInLib;

import android.app.Dialog;

public interface IRDroidInterface  {
    public Dialog buildConfigDialog(int ID);
    // Other method signatures here
}

別のプロジェクトでサンプルプラグインとしてクラスを作成し(そしてそれをapkにエクスポートし)、アプリのファイルディレクトリにプッシュすることができました。

package com.strutton.android.testloadclass;

import com.strutton.android.UIPlugInLib.IRDroidInterface;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.widget.Button;

public class MyTestClass_IRDroidUIPlugIn extends Button implements IRDroidInterface{
    public final Activity mActivity;
    public MyTestClass_IRDroidUIPlugIn(Activity activity) {
        super((Context)activity);
        mActivity = activity;
        setText("I was loaded dynamically! (1)");
        setOnClickListener(new View.OnClickListener() {  
            public void onClick(View v) {  
                setText("I was Clicked dynamically! (" + getId() +")");
            }}  
                );
    }

    public Dialog buildConfigDialog(int ID){
        AlertDialog.Builder builder = new AlertDialog.Builder((Context)mActivity);
        builder.setMessage("Click the Button...(1)")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    mActivity.dialogDismiss();
               }           
           });
        return builder.create();
    }
}

onCreate()次のコードを使用して、実行時にこのクラスをロードし、そのインスタンスを(自分で)作成できます。

package com.strutton.android.testplugin;

        try {
        final File filesDir = this.getFilesDir();
        final File tmpDir = getDir("dex", 0);
        final DexClassLoader classloader = new DexClassLoader( filesDir.getAbsolutePath()+"/testloadclass.apk",
                tmpDir.getAbsolutePath(),
                null, this.getClass().getClassLoader());
        final Class<View> classToLoad = 
                (Class<View>) classloader.loadClass("com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn");
        mybutton = (View) classToLoad.getDeclaredConstructor(Context.class).newInstance(this);
        mybutton.setId(2);
        main.addView((View)mybutton);
      } catch (Exception e) {
        e.printStackTrace();
    }

    setContentView(main);
}
protected Dialog onCreateDialog(int id) {
    switch (id) {
        case 1:
                    // this is the offending line 57
            return ((IRDroidInterface) mybutton).buildConfigDialog(id);
    }
    return null;
}

プラグインで定義された構成ダイアログをプラグインが表示できるようにしたい。電話をかけるbuildConfigDialog(id)と、次のようになりますClassCastException

04-20 20:49:45.865:W / System.err(354):java.lang.ClassCastException:com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn
04-20 20:49:45.894:W / System.err(354) :com.strutton.android.testplugin.TestpluginActivity.onCreate(TestpluginActivity.java:57)で

ここで何が欠けていますか?私は1日半グーグルしていて、解決策を見つけることができません。

前もって感謝します。

4

2 に答える 2

3

問題は、IRDroidInterfaceインターフェイスがアプリケーションとロードするdexファイルの両方に存在することだと思います。MyTestClass_IRDroidUIPlugInクラスを動的にロードすると、これはdexファイルからのものであるため、アプリケーションからではなく、dexファイルからインターフェイスクラスを実装します。

インターフェイスクラスがプラグインのdexファイルに含まれないようにすることができれば、持っているものは問題なく機能するはずです。

残念ながら、Eclipseまたはantを使用してプラグインapkを構築している場合、これを行うのは難しい場合があります。(かなり醜い)解決策の1つは、ビルド後にdexファイルからインターフェイスクラスを削除することです。つまり、baksmaliを使用して分解し、インターフェイスの.smaliファイルを削除してから、smaliを使用して再アセンブルします。

于 2012-04-22T04:29:10.177 に答える
0

DexClassLoaderのカスタム実装を使用して、この問題を解決できます。findclassをオーバーライドし、ライブラリではなくアプリにあるインターフェースのみを返します。

package re.execute;

import dalvik.system.DexClassLoader;

public class DexLoader extends DexClassLoader{
    public DexLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
    super(dexPath, optimizedDirectory, libraryPath, parent);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    if("re.execute.ILoader".equals(name)){
        return ILoader.class;
    }
    return super.findClass(name);
}
}
于 2016-07-15T22:52:07.573 に答える