Упаковка файлов ресурсов Android в распространяемый файл Jar
-
22-09-2019 - |
Вопрос
Я работаю над повторно используемым кодом Android, который хотел бы распространить среди других разработчиков для использования в их собственных приложениях.В коде есть некоторые зависимости ресурсов (макеты, рисунки xml и png), которые я хотел бы иметь возможность включать и ссылаться на них в одном пакете (файл Jar).
Возможно ли это, и если да, то как лучше всего это сделать?
Решение
У меня нет для вас никаких оптимистичных новостей.В общем, вы не можете распространять свой собственный пакет так легко, как вы ожидаете.Основная проблема — автоматически созданный R-файл.Вы, вероятно, делаете на него какие-то ссылки — у вас есть макеты и чертежи.У пользователя вашей библиотеки будет свой собственный файл R, содержащий идентификаторы его ресурсов, а не тех, которые предоставляет ваша библиотека.
В случае доступных ресурсов вы можете прочитать их классическим способом, без R-файла.Но насколько я знаю вы не умеете надувать макеты из внешних xml файлов.
Таким образом, уродливым хаком здесь было бы распространение вашей библиотеки вместе со всеми вашими ресурсами, которые пользователю пришлось бы скопировать в свою папку «res».Честно говоря, хорошего решения вашей проблемы не существует...извини.С уважением!
Другие советы
Поскольку Android делает R
класс автоматически с файлами ресурсов под /res
папку, используя R
класс как final static
невозможно.
Я нашел хорошее решение использовать jar
файл с res
файлы.Вот как я это сделал:
В вашем исходном коде, который будет экспортирован в
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");
Этот метод дает вам идентификатор ресурса во время выполнения.Он использует API отражения для получения статуса
R
во время выполнения.Используя этот метод, вы можете избежать использования
R
переменная.Скопируйте свой
res
файлы в целевой проект.Строить.
макеты:
жесткий код в исходном коде Java
xml и png:
скопируйте xml и png в папку src вашего проекта и упакуйте в jar, например
скопируйте файл .png в src/com/example/test
загрузите его как следующие коды Java:
InputStream is = YourClassName.class.getClassLoader().getResourceAsStream("com/example/test/a.png");
if ( null != is )
{
Bitmap bmp = BitmapFactory.decodeStream(is);
Я только что обнаружил, что aapt
Инструмент в Android 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.
Звучит многообещающе, хотя я этого не пробовал и понятия не имею, работает ли это.Я подозреваю, что это делается для того, чтобы обойти проблему, описанную в сообщении @J.J.Kim выше.
Вы можете динамически получать идентификатор ресурса, используя метод Android.
int preferences = context.getResources().getIdentifier("preferences", "xml", context.getPackageName());
Позже ваши ресурсы необходимо будет включить (скопировать) в ваш новый проект.
я использовал user558185 решение, но есть более простой способ.Если ваши ресурсы находятся в проекте библиотеки (например, для плагина Cordova), вы можете получить ресурс с помощью context.getResources().getIdentifier(name, className, context.getPackageName());
Это происходит, когда файл R ресурсов проекта библиотеки не создается должным образом, а имя пакета R не соответствует требуемому имени пакета в проекте библиотеки.
Использование такое же, как и ответ user558185, но используется собственный метод Android.
Привет, я думаю, что это поздний ответ, но все же мне просто что сообщить об AAR
Android ARchive — этот файл может хранить ваши файлы res и манифеста, чтобы другие разработчики могли просто импортировать aar в свой проект и скомпилировать свой код.
Таким образом, мы можем получить ошибки слияния манифеста, исправить использование свойства replace в вашем манифесте, и это следует проверить перед распространением.
вы можете использовать абстракцию, чтобы получить значения R от реализующего класса (пользователя).
protected abstract void getMyLayoutTextBox(int myLayoutTextBox);
Затем пользователь должен расширить ваш класс (который расширяет Activity
) и реализовать этот метод.В своем классе вы просто звоните getMyLayoutTextBox()
и вы получите правильное значение R, предоставленное пользователем после того, как он реализует ваш распространяемый jar.
Вы можете прочитать больше о абстракция здесь.
Если вы используете Eclipse, перейдите в проект "Properties->Java Build Path"
.На вкладке "Source"
, добавьте папку res, которую хотите упаковать (например.разрешение/сырой).
Он добавит следующую строку в .classpath
файл
<classpathentry kind="src" path="res/raw"/>
После завершения сборки новый файл jar будет содержать файлы в res/raw/
папка.Вы можете получить к ним доступ как user558185 предложенный.