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

时间:2021-06-06 13:29:26

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 drawables),我希望能够在单个包(Jar文件)中包含和引用它们。

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

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

9 个解决方案

#1


26  

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文件。您可能会对它进行一些引用——您有您的布局和drawables。您的库的用户将拥有自己的R文件——包含其资源的id,而不是您的库提供的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”文件夹中。老实说,你的问题没有好的解决办法……对不起。的问候!

#2


54  

Since Android makes the R class automatically with resource files under the /res folder, using the R class as final static is impossible.

由于Android在/res文件夹下使用资源文件自动生成R类,因此不可能使用R类作为最终静态。

I found a nice solution to use a jar file with the res files. Here is how I did it:

我找到了一个很好的解决方案,使用带有res文件的jar文件。我是这样做的:

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

    在将在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;
    }
    

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

    例如,如果您有一个名为main的布局。xml,您可以通过调用方法:

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

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

    如果您有一个id为“text1”的字符串,您可以通过调用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 R at runtime.

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

    By using this method you can avoid using the R variable.

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

  2. Copy your res files to your target project.

    将您的res文件复制到目标项目中。

  3. Build.

    构建。

#3


19  


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

复制一个。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);

#4


4  

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

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

   --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.

这听起来很有希望,尽管我没有尝试过,所以我不知道它是否有效。我怀疑这是为了解决@J.J提出的问题。金的文章。

#5


3  

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.

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

#6


1  

I was using user558185 solution 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(名称、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答案相同,但使用的是原生的Android方法。

#7


1  

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.

这个文件可以保存您的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.

通过这种方式,我们可能会得到Manifest合并错误,在您的Manifest中使用replace属性的修正,这应该在发布之前检查。

#8


0  

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.

然后,用户必须扩展您的类(扩展活动),并实现这个方法。在您的类中,您只需调用getMyLayoutTextBox(),在他实现您的可分配jar之后,您将得到用户提供的正确的R值。

You can read more about abstraction here.

您可以在这里阅读更多有关抽象的内容。

#9


0  

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,请转到项目“Properties->Java构建路径”。在“Source”选项卡下,添加要打包的res文件夹(例如res/raw)。

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

它将在.classpath文件 中添加以下一行

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

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

#1


26  

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文件。您可能会对它进行一些引用——您有您的布局和drawables。您的库的用户将拥有自己的R文件——包含其资源的id,而不是您的库提供的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”文件夹中。老实说,你的问题没有好的解决办法……对不起。的问候!

#2


54  

Since Android makes the R class automatically with resource files under the /res folder, using the R class as final static is impossible.

由于Android在/res文件夹下使用资源文件自动生成R类,因此不可能使用R类作为最终静态。

I found a nice solution to use a jar file with the res files. Here is how I did it:

我找到了一个很好的解决方案,使用带有res文件的jar文件。我是这样做的:

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

    在将在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;
    }
    

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

    例如,如果您有一个名为main的布局。xml,您可以通过调用方法:

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

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

    如果您有一个id为“text1”的字符串,您可以通过调用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 R at runtime.

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

    By using this method you can avoid using the R variable.

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

  2. Copy your res files to your target project.

    将您的res文件复制到目标项目中。

  3. Build.

    构建。

#3


19  


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

复制一个。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);

#4


4  

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

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

   --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.

这听起来很有希望,尽管我没有尝试过,所以我不知道它是否有效。我怀疑这是为了解决@J.J提出的问题。金的文章。

#5


3  

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.

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

#6


1  

I was using user558185 solution 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(名称、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答案相同,但使用的是原生的Android方法。

#7


1  

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.

这个文件可以保存您的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.

通过这种方式,我们可能会得到Manifest合并错误,在您的Manifest中使用replace属性的修正,这应该在发布之前检查。

#8


0  

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.

然后,用户必须扩展您的类(扩展活动),并实现这个方法。在您的类中,您只需调用getMyLayoutTextBox(),在他实现您的可分配jar之后,您将得到用户提供的正确的R值。

You can read more about abstraction here.

您可以在这里阅读更多有关抽象的内容。

#9


0  

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,请转到项目“Properties->Java构建路径”。在“Source”选项卡下,添加要打包的res文件夹(例如res/raw)。

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

它将在.classpath文件 中添加以下一行

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

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