【问题标题】:How to keep a jar file external but still use its classes in my Android project?如何将 jar 文件保留在外部,但仍然在我的 Android 项目中使用它的类?
【发布时间】:2014-12-16 17:32:22
【问题描述】:

我需要一个 jar 文件位于 Android 项目的 main/assets 目录中。重要的是 jar 文件位于那里。

在我的主要 Android 项目中,有没有办法在我的代码中引用这个 jar 文件并使用它的类?

需要明确的是,我不想在编译后将 jar 添加到主项目中。

编辑:我尝试了下面的链接,它似乎加载了我所说的 Class 文件。但我正在努力如何为动态加载的类定义构造函数参数。

android-custom-class-loading-sample

EDIT2

快到了。我已经确认该类是从我的 classes.jar 加载的。不过,我一直在实例化它。

在 licenseValidatorClazz.getConstructor 行上,我收到以下错误。我猜我的接口文件中缺少某些内容?

java.lang.NoSuchMethodException:[接口 com.google.android.vending.licensing.Policy,接口 com.google.android.vending.licensing.DeviceLimiter,接口 com.google.android.vending.licensing.LicenseCheckerCallback,int , 类 java.lang.String, 类 java.lang.String]

    public Class licenseValidatorClazz = null;
    public LicenseValidator validator;

    ...

    // Initialize the class loader with the secondary dex file.
    DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
    optimizedDexOutputPath.getAbsolutePath(),
    null,
    mContext.getClassLoader());

        try {
            // Load the library class from the class loader.
            licenseValidatorClazz = cl.loadClass("com.google.android.vending.licensing.LicenseValidator");

            validator = (LicenseValidator) licenseValidatorClazz.getConstructor(Policy.class,DeviceLimiter.class,LicenseCheckerCallback.class,int.class,String.class,String.class).newInstance(ddd, new NullDeviceLimiter(),
                    callback, generateNonce(), mPackageName, mVersionCode);

        } catch (Exception exception) {
            // Handle exception gracefully here.
            exception.printStackTrace();
        }

我有一个接口,其中包含要传递给加载的类的函数。

public interface LicenseValidator
{
    public LicenseCheckerCallback getCallback();
    public int getNonce();
    public String getPackageName();
    public void verify(PublicKey publicKey, int responseCode, String signedData, String signature);
    public void handleResponse(int response, ResponseData rawData);
    public void handleApplicationError(int code);
    public void handleInvalidResponse();
}

【问题讨论】:

  • 您使用的是哪个构建工具?
  • 我正在使用 Android Studio。

标签: java android jar import external


【解决方案1】:

要使用外部 jar 与您的应用程序关联并在运行时使用它,它需要采用 dalvik 格式,因为普通 jar 无法在 dalvikVM 下工作。

  1. 使用 dx 工具转换文件
  2. 使用 aapt cmd 将这些 classes.dex 添加到您的 jar 文件中。
  3. 现在这个包含 dalvik 格式文件的 jar 可以加载到我们的项目中。

Here 是一篇解释完成它的过程的帖子。

【讨论】:

  • 设法使用 DX 工具。我想我上一堂简单的课就可以了。但我正在尝试将部分 Android LVL 库移动到 jar 中。似乎很棘手。
【解决方案2】:

有一些步骤可以做到这一点。

  1. 您必须将 JAR 文件的副本复制到应用程序的私有内部存储中。

    1. 使用 android 文件夹中的 dx 工具,您必须生成与 JAR 文件关联的 classes.dex 文件。 dx 工具会在 /android-sdks/build-tools/19.0.1 位置(这个文件是 Dalvik VM 需要的,只是 jar 不能被 dalvik VM 读取)

    2. 使用同样位于同一位置的 aapt 工具命令,您必须将 classes.dex 添加到 JAR 文件中。

This JAR 文件可以使用 DexClassLoader 动态加载。

如果您要从任何一个您自己的库中制作 JAR,则每次库源代码发生更改时,您都必须执行此步骤 (1-4)。因此,您可以通过创建 shell 脚本(在 Mac/Linux/Ubuntu 中)或批处理脚本(在 Windows 中)来自动执行这些步骤。您可以参考此链接了解如何编写 shell 脚本。

注意: 实现此方法的一种情况是,无法将JAR 文件直接添加到核心项目的构建路径,需要在运行时动态加载。在正常情况下,可以将 JAR 文件添加到构建路径中。

请查看此链接以获取详细的代码和实现。

How to load a jar file at runtime

Android: How to dynamically load classes from a JAR file?

希望这会有所帮助!!

【讨论】:

    【解决方案3】:

    您应该试用服务 API - java.util.ServiceLoader

    您在 jar 中定义服务接口及其实现。

     package com.my.project;
     public interface MyService { ... }
     public class MyServiceBarImpl implements MyService { ... }
     public class MyServiceFooImpl implements MyService { ... }
    

    然后在 META-INF/services/ 目录中定义 jar 文件中包含的服务。例如,在文件“META-INF/services/com.my.project.MyService”中,您列出了提供程序类。

    # Known MyService providers.
    com.my.project.MyServiceBarImpl  # The original implementation for handling "bar"s.
    com.my.project.MyServiceFooImpl  # A later implementation for "foo"s.
    

    然后,在您的主代码库中,您可以使用 ServiceLoader 实例化一个 MyService 实例:

    for (MyService service : ServiceLoader.load(MyService.class)) {
        //Perform some test to determine which is the right MyServiceImpl
        //and then do something with the MyService instance
    }
    

    这些示例或多或少直接取自 API,尽管我更改了包名称以使其阅读起来稍微不那么烦人。

    【讨论】:

      猜你喜欢
      • 2010-11-23
      • 1970-01-01
      • 2011-01-04
      • 2014-06-16
      • 2014-08-07
      • 2012-05-27
      • 1970-01-01
      • 2013-05-14
      • 2018-06-30
      相关资源
      最近更新 更多