Bibliothèque Android avec ressources substituables
Lorsque l’on distribue une bibliothèque Android compilée, on voudrait parfois que le développeur amené à l’utiliser ait la possibilité d’éditer certaines ressources, lui permettant par exemple de changer une image ou modifier une chaîne de caractères.
Parmi les solutions possibles, on peut fournir une API permettant le changement de ces ressources ou bien demander à l’utilisateur de mettre à jour les ressources de la bibliothèque avec ses données. Cependant, utiliser une API Java pour changer des images et chaînes peut ne pas être très pratique, et changer les ressources de la bibliothèque peut créer des problèmes lorsque la bibliothèque doit être mise à jour, ou encore si la bibliothèque est fournie sous forme de fichier AAR.
Dans ce cas, la meilleure solution serait de permettre au développeur d’ajouter des ressources dans son propre projet, qui remplaceront celles de la bibliothèque.
La solution ici proposée montre comment utiliser les ressources pour leur permettre d’être substituables.
Quand une application Android ou une bibliothèque est compilée, les ressources sont stockées dans un fichier, et une référence est créée dans le fichier R.java. Dans ce fichier R.java, chaque référence est une constante entière dont le nom est celui de la ressource et dont la valeur est un identifiant généré par le compilateur.
Pour charger une ressource pouvant avoir été remplacée par le développeur qui utilise notre bibliothèque, nous aurons besoin lors de l’exécution d’obtenir l’identifiant basé sur le nom. Si la ressource n’existe pas dans les ressources principales de l’application, c’est alors la ressource de la bibliothèque qui est automatiquement utilisée.
Pour obtenir à l’exécution l’identifiant de la ressource, on utilise la méthode getIdentifier de la classe Resources.
La syntaxe est :
getIdentifier(java.lang.String name, java.lang.String type, java.lang.String package)
où :
- name est le nom de la ressource ;
- type est la chaîne contenant le type de ressource, comme : anim, attr, color, drawable, id, integer, layout, menu, string, style, etc. ;
- package est le paquetage de l’application principale.
Pour obtenir le nom du paquet de l’application principale au moment de l’exécution, la solution simple est d’utiliser la méthode getPackageName à partir d’un contexte.
Une fois l’identifiant obtenu, vous pouvez charger la ressource avec les méthodes de Resources, comme :
- getString,
- getLayout,
- getDrawable,
- etc.
Pour obtenir une référence sur l’objet Ressources de votre application, il suffit d’utiliser la méthode getResources à partir d’un contexte.
Le seul problème avec cette solution est que les ressources qui doivent être substituées doivent être chargées au moment de l’exécution. Cela signifie que, par exemple, les références aux ressources utilisées dans un layout XML ne peuvent pas être substituées. Ainsi, si vous souhaitez qu’une chaîne de caractère dans une mise en page soit remplaçable, vous devez mettre à jour le contenu de l’interface utilisateur quand celle-ci est créée (dans la méthode onCreate par exemple) en chargeant la ressource en utilisant la solution décrite ci-dessus.
Notez que lors de l’utilisation de cette méthode, les ressources manquantes ne seront pas détectées au moment de la compilation. Vous devez donc faire attention.
Cette technique fonctionne pour tous les types de ressources : drawable, string, layout, theme, color, etc.
Notez que si vous utilisez un outil tel que Proguard pour masquer votre code source, vous devrez absolument vous assurer que le fichier de ressource (R.class) de la librairie est exclu du processus de masquage, ou votre application ne fonctionnera pas.