web-dev-qa-db-fra.com

Emballage de fichiers de ressources Android dans un fichier Jar distribuable

Je travaille sur un code Android réutilisable que je souhaiterais distribuer à d'autres développeurs pour l'utiliser dans leurs propres applications. Le code comporte des dépendances de ressources (mises en forme, tirages xml et png) que je voudrais pouvoir inclure et référencer dans un seul package (fichier Jar).

Est-ce possible et, dans l'affirmative, quelle est la meilleure méthode pour le faire?

47
Jeff Gilfelt

Je n'ai aucune nouvelle optimiste pour vous. En général, vous ne pouvez pas distribuer votre propre paquet aussi facilement que prévu. Le problème principal est le fichier R auto-généré. Vous en faites probablement des références - vous avez vos mises en page et vos tirables. L'utilisateur de votre bibliothèque aura son propre fichier R - contenant les identifiants pour ses ressources, pas pour ceux fournis par votre bibliothèque. 

Dans le cas de ressources extractibles, vous pouvez les lire de manière classique, sans le fichier R. Mais pour autant que je sache, vous n'êtes pas en mesure de gonfler les mises en page à partir de fichiers XML externes. 

Donc, le vilain piratage ici serait de distribuer votre bibliothèque avec toutes vos ressources, quel utilisateur devrait copier dans son dossier "res" Pour être honnête, il n’ya pas de bonne solution à votre problème ... désolé . Amicalement!

26
Ramps

Étant donné qu'Android crée automatiquement la classe R avec des fichiers de ressources dans le dossier /res, il est impossible d'utiliser la classe R en tant que final static.

J'ai trouvé une solution intéressante pour utiliser un fichier jar avec les fichiers res. Voici comment je l'ai fait:

  1. Dans votre code source qui sera exporté dans le fichier jar, n’utilisez pas de variable R car elle sera remplacée par une adresse mémoire statique finale au moment de la compilation ..__ Au lieu d’utiliser R, j’ai créé méthode ci-dessous:

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

    Par exemple, si vous avez une disposition nommée main.xml, vous pouvez l'obtenir en appelant la méthode suivante:

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

    Si vous avez une chaîne dont id est "text1", vous pouvez l'obtenir en appelant la méthode

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

    Cette méthode vous donne votre identifiant de ressource au moment de l'exécution. Il utilise l'API de réflexion pour obtenir le statut de R au moment de l'exécution.

    En utilisant cette méthode, vous pouvez éviter d'utiliser la variable R.

  2. Copiez vos fichiers res dans votre projet cible.

  3. Construire.

54
J.J. Kim

mises en page: 

code dur dans votre source Java


xml & png: 

copier xml & png dans le dossier src de votre projet et le package dans jar, par exemple

copier a.png vers src/com/exemple/test

chargez-le sous les codes Java suivants:

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

Je viens de constater que l'outil aapt du SDK Android permet l'option suivante:

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

Cela semble prometteur, bien que je n’aie pas essayé cela et que je ne sache pas si cela fonctionne. Je suppose que cela a pour but de résoudre le problème traité par le message de @ J.J.Kim ci-dessus.

4
scorpiodawg

Vous pouvez obtenir de manière dynamique un identifiant de ressource à l'aide de la méthode Android.

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

Plus tard, vos ressources doivent être incluses (copiées) dans votre nouveau projet.

3
Konrad Nowicki

Bonjour, je pense que la réponse est tardive, mais j’ai encore de quoi informer sur AAR.

Android ARchive - ce fichier peut contenir vos fichiers res et manifestes, de sorte que les autres développeurs puissent simplement importer le fichier aar dans leur projet et compiler leur code.

De cette façon, nous pourrions obtenir des erreurs de fusion de manifeste, le correctif qui lui permettrait d'utiliser la propriété de remplacement dans votre manifeste, ce qui devrait être vérifié avant la distribution.

1
Vimalanathan

J'utilisais user558185 solution mais voici un moyen plus simple. Si vos ressources sont dans un projet de bibliothèque (pour un plugin Cordova par exemple), vous pouvez obtenir une ressource avec context.getResources().getIdentifier(name, className, context.getPackageName());

Cela se produit lorsque le fichier R des ressources du projet de bibliothèque n'est pas généré correctement et que le package R ne correspond pas au packageName requis par le projet de bibliothèque.

L'utilisation est la même que la réponse user558185, mais il utilise une méthode Android native. 

1
Hugo Gresse

Si vous utilisez Eclipse, accédez au projet "Properties->Java Build Path". Sous l'onglet "Source", ajoutez le dossier res que vous voulez emballer (par exemple, res/raw).

Il va ajouter la ligne suivante dans le fichier .classpath
<classpathentry kind = "src" chemin = "res/raw" />

Une fois la construction terminée, le nouveau fichier JAR contiendra les fichiers du dossier res/raw/. Vous pouvez y accéder en tant que user558185 suggéré.

0
june232

vous pouvez utiliser l'abstraction pour obtenir les valeurs R de la classe d'implémentation (l'utilisateur).

protected abstract void getMyLayoutTextBox(int myLayoutTextBox);

Ensuite, l'utilisateur doit étendre votre classe (qui étend Activity) et implémenter cette méthode. Dans votre classe, vous appelez simplement getMyLayoutTextBox() et vous obtiendrez la valeur R correcte fournie par l'utilisateur après la mise en œuvre de votre jar distribuable.

Vous pouvez en savoir plus sur abstraction ici .

0
CrackerJack9