7

.apk ファイルの /assets ディレクトリにある jar ファイルからインターフェイスのプラグイン実装をロードしようとしています。これを機能させる唯一の方法は、jar ファイルをプライベート外部ストレージに抽出し、そのファイルを DexClassLoader に渡すことです。

それは機能しますが、jar が 2 つの場所 (.apk とプライベート外部ストレージ) に存在する必要があるのはなぜですか? DexClassLoader には、引数としてファイル パスが必要です。

/assets フォルダーにあるファイルへの直接パスを指定して、既に存在するものの余分なコピーのために外部ストレージを使い果たす必要がないようにする方法はありますか?

関連するコード スニペットは次のとおりです。

// somewhere in my main Activity ...
  final File aExtractedDexFile = new File(getDir("dex", Context.MODE_PRIVATE),
                                  LIBRARY_DEX_JAR);
  extractDexTo(aExtractedDexFile);
  loadLibraryProvider(aExtractedDexFile);

/** Extract the jar file that contains the implementation class.dex and place in private storage */
private void extractDexTo(File tJarInternalStoragePath) {
  BufferedInputStream aJarInputStream = null;
  OutputStream aDexOutputStream = null;

  try {
    aJarInputStream = new BufferedInputStream(getAssets().open(LIBRARY_DEX_JAR));
    aJarOutputStream = new BufferedOutputStream(new FileOutputStream(tJarInternalStoragePath));
    byte[] buf = new byte[BUF_SIZE];
    int len;
    while ((len = aJarInputStream.read(buf, 0, BUF_SIZE)) > 0)
    {
      aJarOutputStream.write(buf, 0, len);
    }
    aJarOutputStream.close();
    aJarInputStream.close();
  } catch (IOException e) {
    if (aDexOutputStream != null) {
      try {
        aJarOutputStream.close();
      } catch (IOException ioe) {
        ioe.printStackTrace();
      }
    }

    if (aJarInputStream != null) {
      try {
        aJarInputStream.close();
      } catch (IOException ioe) {
        ioe.printStackTrace();
      }
    }
  }
}

/** Use DexClassLoader to load the classes from LibraryProvider */
private void loadLibraryProvider(File tFile) {
  // Internal storage where the DexClassLoader writes the optimized dex file to.
  final File aOptimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE);

  // Initialize the class loader with the secondary dex file.
  DexClassLoader cl = new DexClassLoader(tFile.getAbsolutePath(),
          aOptimizedDexOutputPath.getAbsolutePath(),
          null,
          getClassLoader());
  Class<?> aLibProviderClazz = null;

  try {
    // Load the library class from the class loader.
    aLibProviderClazz = cl.loadClass(LIBRARY_PROVIDER_CLASS);      
    sLibraryProvider = (LibraryInterface) aLibProviderClazz.newInstance();
  } catch (Exception exception) {
    // Handle exception gracefully here.
    exception.printStackTrace();
  }
}
4

1 に答える 1

3

/assets フォルダーにあるファイルへの直接パスを指定して、既に存在するものの余分なコピーのために外部ストレージを使い果たす必要がないようにする方法はありますか?

答えはノーです。コードを実装する公式ソースが投稿したこのブログをフォローしていると思います。より良い方法があれば、ブロガーは自分のブログでそれを推奨する必要があります。

最適化されたディレクトリが必要な理由は、APIで説明されています。

このクラス ローダーには、最適化されたクラスをキャッシュするためのアプリケーション プライベートな書き込み可能なディレクトリが必要です。

また、アセット ディレクトリは apk で書き込み可能ではないため、純粋なアセット ディレクトリでは実行できないことに注意してください。

jar ファイルのコピーが必要な理由は、ブログで言及されているように、少し微妙です。

まず、パスをクラスローダーに提供できるストレージの場所にコピーする必要があります。

apk アーカイブに埋め込まれたすべて (フォルダー/ファイル) は、実行時に基になるファイル システムに公開 (または解釈) できません。つまり、 DexClassLoaderと PathClassLoader のコンストラクターの両方で必要な dexPath には/data/data/com.example/dex/common-lib.jar、ファイル システム内のファイルを表すような堅実なパス文字列が必要です。

于 2012-05-09T00:02:41.817 に答える