Упаковка файлов ресурсов Android в распространяемом файле Jar
Я работаю над некоторым многоразовым кодом Android, который я бы хотел распространять другим разработчикам для использования в своих приложениях. Код имеет некоторые зависимости ресурсов (макеты, xml и png drawables), которые я хотел бы иметь возможность включать и ссылаться в одном пакете (файл Jar).
Возможно ли это, и если да, то каков наилучший способ сделать это?
Ответы
Ответ 1
У меня нет оптимистических новостей для вас. В общем, вы не можете распространять свой собственный пакет так же легко, как и следовало ожидать. Основная проблема заключается в автогенерированном файле R. Вы, вероятно, делаете некоторые ссылки на него - у вас есть свои макеты и чертежи. Пользователь вашей библиотеки будет иметь свой собственный R файл, содержащий идентификаторы для его ресурсов, а не те, которые предоставляет ваша библиотека.
В случае доступных ресурсов вы можете читать их классическим способом, без R файла. Но насколько я знаю, вы не можете раздувать макеты из внешних xml файлов.
Таким образом, уродливый хак здесь будет распространять вашу библиотеку вместе со всеми вашими ресурсами, которые пользователь должен будет скопировать в свою папку "res". Честно говоря, нет хорошего решения вашей проблемы... извините.
Привет!
Ответ 2
Так как 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
в целевой проект.
-
Построить.
Ответ 3
макеты:
жесткий код в исходном тексте java
xml и png:
скопировать xml и png в папку src проекта и пакет в jar, например
скопировать a.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);
Ответ 4
Я только что обнаружил, что инструмент 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 выше.
Ответ 5
Вы можете динамически получать идентификатор ресурса с помощью метода android.
int preferences = context.getResources().getIdentifier("preferences", "xml", context.getPackageName());
Позже ваши ресурсы должны быть включены (скопированы) в ваш новый проект.
Ответ 6
Я использовал user558185, но вот более простой способ. Если ресурсы находятся в проекте библиотеки (например, для плагина Кордовы), вы можете получить ресурс с помощью context.getResources().getIdentifier(name, className, context.getPackageName());
Это происходит, когда файл ресурсов ресурсов библиотеки библиотеки не генерируется должным образом, а имя пакета R не соответствует требуемому имени пакета в проекте библиотеки.
Использование совпадает с ответом user558185, но использует собственный метод Android.
Ответ 7
Привет, я думаю, что это поздний ответ, но все же я просто хочу сообщить об AAR
Android ARchive - этот файл может содержать ваши файлы res и манифеста, так что другой разработчик может просто импортировать aar в свой проект и скомпилировать свой код.
Таким образом, мы можем получить ошибки слияния манифеста, исправление для использования функции replace в вашем манифесте, и это должно быть проверено перед распространением.
Ответ 8
вы можете использовать абстракцию, чтобы получить значения R из класса реализации (пользователь).
protected abstract void getMyLayoutTextBox(int myLayoutTextBox);
Затем пользователь должен расширить ваш класс (который расширяет Activity
) и реализовать этот метод. В своем классе вы просто вызываете getMyLayoutTextBox()
, и у вас будет правильное значение R, предоставленное пользователем после того, как он реализует вашу распределяемую банку.
Подробнее о абстракции здесь.
Ответ 9
Если вы используете Eclipse, перейдите в проект "Properties->Java Build Path"
. В вкладке "Source"
добавьте папку res, в которую вы хотите упаковать (например, res/raw).
Он добавит следующую строку в файл .classpath
< classpathentry kind =" src "path =" res/raw"/ >
После завершения сборки новый файл jar будет содержать файлы в папке res/raw/
. Вы можете получить к ним доступ как user558185.