在可分发的 Jar 文件中打包 Android 资源文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1995004/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:06:20  来源:igfitidea点击:

Packaging Android resource files within a distributable Jar file

androidandroid-resources

提问by Jeff Gilfelt

I am working on some reusable Android code that I would like to distribute to other developers for use within their own applications. The code has some resource dependencies (layouts, xml & png drawables) that I would like to be able to include and reference within a single package (Jar file).

我正在研究一些可重用的 Android 代码,我想将这些代码分发给其他开发人员,以便在他们自己的应用程序中使用。该代码具有一些资源依赖项(布局、xml 和 png 可绘制对象),我希望能够在单个包(Jar 文件)中包含和引用这些资源。

Is this possible, and if so what is the best method to do this?

这是可能的,如果是这样,最好的方法是什么?

采纳答案by Ramps

I don't have any optimistic news for you. In general you cannot distribute your own package as easily as you would expect. The main problem is the autogenerated R file. You probably make some references to it - you have your layouts and drawables. User of your library will have his own R file - containing ids for his resources, not for the ones your library provides.

我没有什么好消息要告诉你。通常,您无法像预期的那样轻松分发自己的软件包。主要问题是自动生成的 R 文件。您可能对它进行了一些参考 - 您有自己的布局和可绘制对象。您图书馆的用户将拥有他自己的 R 文件 - 包含他的资源的 ID,而不是您的图书馆提供的资源。

In case of drawable resources you could read them in classic way, without R file. But as far as I know you are not able to inflate layouts from external xml files.

对于可绘制资源,您可以以经典方式读取它们,而无需 R 文件。但据我所知,您无法从外部 xml 文件中扩展布局。

So the ugly hack here would be to distribute your library together with all your resources, which user would have to copy to his "res" folder. To be honest, there is no good solution to your problem... sorry. Regards!

因此,这里的丑陋技巧是将您的库与所有资源一起分发,用户必须将其复制到他的“res”文件夹中。老实说,您的问题没有好的解决方案......抱歉。问候!

回答by J.J. Kim

Since Android makes the Rclass automatically with resource files under the /resfolder, using the Rclass as final staticis impossible.

由于AndroidR自动使用文件/res夹下的资源文件创建R类,final static因此无法使用该类。

I found a nice solution to use a jarfile with the resfiles. Here is how I did it:

我找到了一个很好的解决方案来将jar文件与文件一起使用res。这是我如何做到的:

  1. In your source code which will be exported in the jarfile, don't useRvariable because it will be replaced with a final static memory address in compile time. Instead of using R, I made my own method below:

    public static int getResourceIdByName(String packageName, String className, String name) {
        Class r = null;
        int id = 0;
        try {
            r = Class.forName(packageName + ".R");
    
            Class[] classes = r.getClasses();
            Class desireClass = null;
    
            for (int i = 0; i < classes.length; i++) {
                if (classes[i].getName().split("\$")[1].equals(className)) {
                    desireClass = classes[i];
    
                    break;
                }
            }
    
            if (desireClass != null) {
                id = desireClass.getField(name).getInt(desireClass);
            }
    
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    
        return id;
    }
    

    For example, if you have a layout named main.xml, you can get it by calling the method:

    int id = getResourceIdByName(context.getPackageName(), "layout", "main");
    

    If you have a string whose idis "text1", you can get it by calling method

    int id = getResourceIdByName(context.getPackageName(), "string", "text1");
    

    This method gives you your resource id at runtime. It uses the reflection API to get the status of Rat runtime.

    By using this method you can avoid using the Rvariable.

  2. Copy your resfiles to your target project.

  3. Build.

  1. 在将导出到jar文件中的源代码中,不要使用R变量,因为它将在编译时被最终静态内存地址替换。R我没有使用,而是在下面创建了自己的方法:

    public static int getResourceIdByName(String packageName, String className, String name) {
        Class r = null;
        int id = 0;
        try {
            r = Class.forName(packageName + ".R");
    
            Class[] classes = r.getClasses();
            Class desireClass = null;
    
            for (int i = 0; i < classes.length; i++) {
                if (classes[i].getName().split("\$")[1].equals(className)) {
                    desireClass = classes[i];
    
                    break;
                }
            }
    
            if (desireClass != null) {
                id = desireClass.getField(name).getInt(desireClass);
            }
    
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    
        return id;
    }
    

    例如,如果您有一个名为 的布局main.xml,则可以通过调用该方法来获取它:

    int id = getResourceIdByName(context.getPackageName(), "layout", "main");
    

    如果你有一个id“text1”的字符串,你可以通过调用方法来获取它

    int id = getResourceIdByName(context.getPackageName(), "string", "text1");
    

    此方法在运行时为您提供资源 ID。它使用反射 API 来获取R运行时的状态。

    通过使用此方法,您可以避免使用R变量。

  2. res文件复制到目标项目。

  3. 建造。

回答by user558185



layouts:

布局:

hard code in your java source

java源代码中的硬代码



xml & png:

xml & png:

copy xml & png to your project src folder and package to jar, for example

例如,将 xml & png 复制到您的项目 src 文件夹并打包到 jar

copy a.png to src/com/example/test

将 a.png 复制到 src/com/example/test

load it as following java codes:

将其加载为以下 java 代码:

    InputStream is = YourClassName.class.getClassLoader().getResourceAsStream("com/example/test/a.png");
    if ( null != is )
    {
          Bitmap bmp = BitmapFactory.decodeStream(is);

回答by scorpiodawg

I just found that the aapttool in the Android SDK allows the following option:

我刚刚发现aaptAndroid SDK 中的工具允许以下选项:

   --non-constant-id
       Make the resources ID non constant. This is required to make an R java class
       that does not contain the final value but is used to make reusable compiled
       libraries that need to access resources.
   --non-constant-id
       Make the resources ID non constant. This is required to make an R java class
       that does not contain the final value but is used to make reusable compiled
       libraries that need to access resources.

This sounds promising, though I have not tried this so I haven't a clue if it works. I suspect this is to get around the problem addressed by @J.J.Kim's post above.

这听起来很有希望,但我还没有尝试过,所以我不知道它是否有效。我怀疑这是为了解决上面@JJKim 的帖子所解决的问题。

回答by Konrad Nowicki

You can dynamically get resource id using android method.

您可以使用 android 方法动态获取资源 ID。

int preferences = context.getResources().getIdentifier("preferences", "xml", context.getPackageName());

Later your resources have to be included (copied) to your new project.

稍后您的资源必须包含(复制)到您的新项目中。

回答by Hugo Gresse

I was using user558185solution but here is a more simple way. If you resources is in a library project (for a Cordova Plugin for example), you can get resource with context.getResources().getIdentifier(name, className, context.getPackageName());

我使用的是user558185解决方案,但这里有一个更简单的方法。如果您的资源位于库项目中(例如 Cordova 插件),您可以使用context.getResources().getIdentifier(name, className, context.getPackageName());

This happen when the library project resources R file is not generated properly and the R packageName did not match the required packageName by the library project.

当库项目资源 R 文件未正确生成并且 R packageName 与库项目所需的 packageName 不匹配时,会发生这种情况。

The usage is the same as user558185 answer, but it use a native Android method.

用法与 user558185 answer 相同,但它使用原生 Android 方法。

回答by Vimalanathan

Hi i think this is a late response but still i just what to inform about AAR

嗨,我认为这是一个迟到的回复,但我仍然只是要告知有关 AAR 的信息

Android ARchive - this file can hold your res and manifest files, so that the other develop can just import the aar to their project and compile their code.

Android ARchive - 该文件可以保存您的 res 和 manifest 文件,以便其他开发人员可以将 aar 导入他们的项目并编译他们的代码。

This way we might get Manifest merge errors, the fix for it to use replace property in your manifest and this should be checked before distribution.

这样我们可能会得到清单合并错误,修复它在清单中使用替换属性,这应该在分发前检查。

回答by june232

If you are using Eclipse, go to project "Properties->Java Build Path". Under tab "Source", add the res folder you want to pack (e.g. res/raw).

如果您使用的是 Eclipse,请转到 project "Properties->Java Build Path"。在 tab 下"Source",添加要打包的 res 文件夹(例如 res/raw)

It will add the following line into the .classpathfile
<classpathentry kind="src" path="res/raw"/>

它将将以下行添加到.classpath文件
<classpathentry kind="src" path="res/raw"/>

After building done, the new jar file will contain the files in res/raw/folder. You can access them as user558185suggested.

构建完成后,新的 jar 文件将包含文件res/raw/夹中的文件。您可以按照user558185 的建议访问它们。

回答by CrackerHyman9

you can use abstraction to get the R values from the implementing class (the user).

您可以使用抽象从实现类(用户)获取 R 值。

protected abstract void getMyLayoutTextBox(int myLayoutTextBox);

Then the user has to extend your class (which extends Activity), and implement this method. In your class, you just call getMyLayoutTextBox()and you'll have the correct R value supplied by the user after he implements your distributable jar.

然后用户必须扩展您的类(即 extends Activity),并实现此方法。在您的课程中,您只需调用getMyLayoutTextBox(),在用户实现您的可分发 jar 后,您就会获得用户提供的正确 R 值。

You can read more about abstraction here.

您可以在此处阅读有关抽象的更多信息。