如何从包装在我的.apk文件中的JAR文件中加载的类? [英] How can I load a class from a jar file packaged in my .apk file?

查看:163
本文介绍了如何从包装在我的.apk文件中的JAR文件中加载的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图加载插件实现的接口从一个jar文件是在我的.apk文件/目录下的资产。我已经能够得到这个工作的唯一方法是通过提取jar文件私人外部存储并传送文件到DexClassLoader。

这样的作品,但为什么罐子里有两个地方(的.apk文件和专用外部存储)存在?该DexClassLoader必须有一个文件路径作为参数。

有没有办法给它一个直接的路径是在/资产文件夹中的文件,这样我就不必使用了外部存储的是什么已经是一个额外的复制present?

下面是相关code片段:

  //地方在我的主要活动...
  最终文件aExtractedDexFile =新的文件(GETDIR(地塞米松,Context.MODE_PRIVATE)
                                  LIBRARY_DEX_JAR);
  extractDexTo(aExtractedDexFile);
  loadLibraryProvider(aExtractedDexFile);
 

  / **提取包含实现class.dex并将其放置在专用存储* jar文件/
私人无效extractDexTo(文件tJarInternalStoragePath){
  的BufferedInputStream aJarInputStream = NULL;
  OutputStream的aDexOutputStream = NULL;

  尝试 {
    aJarInputStream =新的BufferedInputStream(getAssets()开(LIBRARY_DEX_JAR)。);
    aJarOutputStream =新的BufferedOutputStream(新的FileOutputStream(tJarInternalStoragePath));
    byte []的BUF =新的字节[BUF_SIZE]
    INT LEN;
    而((LEN = aJarInputStream.read(buf中,0,BUF_SIZE))大于0)
    {
      aJarOutputStream.write(BUF,0,的len);
    }
    aJarOutputStream.close();
    aJarInputStream.close();
  }赶上(IOException异常E){
    如果(aDexOutputStream!= NULL){
      尝试 {
        aJarOutputStream.close();
      }赶上(IOException异常IOE){
        ioe.printStackTrace();
      }
    }

    如果(aJarInputStream!= NULL){
      尝试 {
        aJarInputStream.close();
      }赶上(IOException异常IOE){
        ioe.printStackTrace();
      }
    }
  }
}
 

  / **使用DexClassLoader从LibraryProvider加载类* /
私人无效loadLibraryProvider(文件tFile){
  //内部存储,其中DexClassLoader写入优化DEX文件。
  最终文件aOptimizedDexOutputPath = GETDIR(outdex,Context.MODE_PRIVATE);

  //初始化类加载器与二次DEX文件。
  DexClassLoader CL =新DexClassLoader(tFile.getAbsolutePath()
          aOptimizedDexOutputPath.getAbsolutePath(),
          空值,
          getClassLoader());
  类<> aLibProviderClazz = NULL;

  尝试 {
    //从类装载器装载库类。
    aLibProviderClazz = cl.loadClass(LIBRARY_PROVIDER_CLASS);
    sLibraryProvider =(LibraryInterface)aLibProviderClazz.newInstance();
  }赶上(例外的例外){
    //处理异常优雅地在这里。
    exception.printStackTrace();
  }
}
 

解决方案

有没有办法给它一个直接的路径是在/资产文件夹中的文件,这样我就不必使用了外部存储什么是一个额外的副本已经present?

答案是:不,我想你跟着的这个博客张贴实现您的code的官方消息。如果有做事情的一个更好的方式,bloger应建议在他的博客。

原因,你需要的 optimizedDirectory 解释在API

  

本类装载器需要一个应用程序专用的,可写目录缓存优化类。

另外请注意,资产目录是不可写的apk文件,因此它不能与纯粹的资产目录来完成的。

原因,你需要复制jar文件是有点微妙,在博客中提到:

  

首先,它被复制到一个存储位置的路径可被提供给类装入器。

嵌入式APK档案中未曝光的一切(文件夹/文件)(或跨preTABLE)在运行时基本的文件系统。换句话说, dexPath 在这两个DexClassLoader要求和PathClassLoader的构造需要像一个坚实的路径字符串 /data/data/com.example/dex/common-lib.jar 的重新presents文件中的文件系统。

I am trying to load a plugin implementation of an interface from a jar file which is in the /assets directory of my .apk file. The only way I've been able to get this to work is by extracting the jar file to private external storage and then passing that file to the DexClassLoader.

That works, but why should the jar have to exist in two places (the .apk and private external storage)? The DexClassLoader has to have a file path as its argument.

Is there a way to give it a direct path to the file that is in the /assets folder so that I don't have to use up external storage for an extra copy of what's already present?

Here are the relevant code snippets:

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

and

/** 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();
      }
    }
  }
}

and

/** 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();
  }
}

解决方案

Is there a way to give it a direct path to the file that is in the /assets folder so that I don't have to use up external storage for an extra copy of what's already present?

The answer is No. I suppose you follow this blog posted by official source implementing your code. if there is a better way of doing things, the bloger should recommend it in his blog.

Reason why you need optimizedDirectory is explained in the API:

This class loader requires an application-private, writable directory to cache optimized classes.

Also note that assets directory is not writable in apk, so it can't be done with purely assets directory.

Reason why you need copy jar file is a little bit subtle, mentioned in the blog:

First, it has to be copied to a storage location whose path can be supplied to the class loader.

Everything (folders/files) embedded within apk archive is not exposable (or interpretable) to the underlying file system at runtime. In another word, dexPath required in both DexClassLoader and PathClassLoader's constructor need a solid path string like /data/data/com.example/dex/common-lib.jar that represents the file in file system.

这篇关于如何从包装在我的.apk文件中的JAR文件中加载的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆