如何从导入它的应用程序配置 Android 库?

How to configure Android library from an app that imports it?

我对 Android 开发有点陌生,所以我的问题可能很奇怪,甚至不可能。我不知道!

无论如何,我正在构建多个将具有大量共享元素的应用程序,因此我决定使用这些组件构建一个库并在所有应用程序中使用它,而不是愚蠢的复制和粘贴代码。 例如,库处理欢迎屏幕和 login/signup 流程活动等。所以这里是这种方法可能导致的问题:

  1. 虽然各个应用程序的行为相同,但我在欢迎屏幕上显示的徽标不同。现在我用图书馆资源 (R class) 中的图像资源填充它,这对所有应用程序都是一样的,显然是不正确的。
  2. login/signup 进程基于 Firebase,这将要求应用程序拥有密钥才能使用它们。现在我还用图书馆资源中的虚拟字符串资源填充它。

所以我的问题实际上可以归结为 3 个部分:

  1. 我是否可以将此信息从应用程序传递到图书馆?我可以以某种方式修改库的 R class 吗?或者我可以使用库中应用程序的 R class 吗?我也可以将库的这一部分作为传递我需要的参数的函数来调用。但第一个解决方案对我来说可能更干净?
  2. 无论问题 1 的答案是什么。我会在哪里以及如何做?图书馆有欢迎 activity 本身,这应该是应用程序中的第一个 activity。在应用程序启动后和第一个 activity 启动之前,如何以及在何处执行此操作?
  3. 如果我做的是错误的或不可能的,有没有其他方法可以实现它?
  1. Is there anyway I could pass this info from the app to the library? can I somehow modify the R class of the library? Or can I use the app's R class from the library? I can also call this part of the library as a function passing the parameters I need. But the first solution looks maybe more clean to me?

您不需要修改R class,因为您可以通过创建同名文件来覆盖资源文件。但这不是一个干净的解决方案,因为您经常需要确保您的项目和库资源名称相同。

  1. Whatever the answer to Q1 is. Where would I do this and how? The library has the welcome activity itself which is supposed to be the first activity in the app. How and where do I do this once the app starts and before the first activity starts?

与其覆盖资源名称,不如修改您的库以接收配置作为使用该库的合同。这里的示例:

首先,创建class用于保存配置:

public class Configuration {
  private int welcomeImageDrawableId;
  private int logoDrawableId;

  // constructor
  public Configuration(int welcomeImageDrawableId, int logoDrawableId) {
    this.welcomeImageDrawableId = welcomeImageDrawableId;
    this.logoDrawableId = logoDrawableId;
  }

  // setter and getter.
  public int getLogoDrawableId() {
    return logoDrawableId;
  }
}

其次,通过创建一个Singleton [=43=,为库使用配置class ] 将由图书馆内部使用:

public class MyLibrary {
    private static MyLibrary myLibrary;
    private Configuration configuration;

    private MyLibrary(){}
    private MyLibrary(Configuration configuration) {
      this.configuration = configuration;
    }

    public static MyLibrary getInstance() {
        if(myLibrary == null) {
            throw new RuntimeException("Need call createInstanceWith method first!!");
        }
        return myLibrary;
    }

    public static MyLibrary createInstanceWith(Configuration configuration) {
        if(myLibrary == null) {
            synchronized(MyLibrary.class) {
                if (myLibrary == null) {
                  myLibrary = new MyLibrary(configuration);
                }
            }
        }
        return test;
    }

    public Configuration getConfiguration() {
      return configuration;
    }
}

第三,通过单例class在你的库中使用配置class。像这样:

// assume imvLogo is an existing ImageView
Configuration configuration = MyLibrary.getInstance().getConfiguration();
imvLogo.setImageResource(configuration.getLogoDrawableId());

最后,当库使用时注册合约:

Configuration configuration = new Configuration(R.drawable.welcome, R.drawable.logo);
MyLibrary.createInstanceWith(configuration);

注意:所有代码尚未测试,错误在所难免。

除了上述解决方案之外,我还找到了另一种无需初始化库等即可实现这一切的方法。 我认为执行此操作的正确方法是在库中使用 productFlavors。这允许库共享一组主要的源代码、一组主要的资源,然后每个 app/flavors 共享一组额外的资源。这对我的目的来说已经足够了。

有关构建变体和风格的更多信息: https://developer.android.com/studio/build/build-variants