Specifying Android project dependencies (in Eclipse) - android

I have two Android projects, a 'library project' containing a custom layout, and an 'application project' containing an application which uses the layout.
Everything seems to build and execute fine, except that the visual layout editor throws a ClassNotFoundException (which I assume is a bug in the plug-in), but when I try to start to make use of the attributes I defined for the custom layout in the xml, I can no longer build. That is; this works:
<?xml version="1.0" encoding="utf-8"?>
<se.fnord.android.layout.PredicateLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asdfasdf"
/>
</se.fnord.android.layout.PredicateLayout>
Whereas this does not:
<?xml version="1.0" encoding="utf-8"?>
<se.fnord.android.layout.PredicateLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fnord="http://schemas.android.com/apk/res/se.fnord.android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
fnord:layout_horizontalSpacing="1px"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asdfasdf"
/>
</se.fnord.android.layout.PredicateLayout>
The build fails with a message from aapt:
ERROR No resource identifier found for attribute 'layout_horizontalSpacing' in package 'se.fnord.android'
The resource identifier does exist in the R-file and attrs.xml contained the library project, and if I put the layout code and resources directly in the application project everything works fine. The layout_horizontalSpacing attribute (and layout_verticalSpacing) is a custom attribute used in the PredicateLayout.LayoutParam class to specify the distance to the next widget.
So far I've tried the standard eclipse ways by specifying project references and build path project dependencies. I was also told to try the tag in the application manifest, which did not help.
So, what do I need to do for the references in the xml-file to work?
I don't know if it's relevant, but the 'library' manifest looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.fnord.android"
android:versionCode="1" android:versionName="1.0.0">
</manifest>
The 'application' manifest like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.fnord.appname"
android:versionCode="1" android:versionName="1.0.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".AppName"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(The 'PredicateLayout', btw, is a cleaned-up version of this).

The earliest versions of Android sdk did not support sharing at the source code level in a nice way. You could jar up your .class files and then add that into the lib/ folder, but this solution did not allow direct sharing of source code and just as importantly did not support the sharing of resources or aidl files.
Then in May 2010, Android introduced the Library Project mechanism. A Library Project is structured very similar to a normal Android project, but rather than being used to produce an apk, it serves only to provide code and resources to other projects. Like an ordinary project, a Library Project usually contains src and res folders, along with an AndroidManifest.xml file; however the manifest should be mostly empty with the exception of the manifest element and the package attribute (no longer true - you can now declare Activities and other components in the manifest of your Library Project). In addition, the project.properties file for a Library Project needs to contain the property:
"android.library=true"
To make a reference from an ordinary (apk-producing) project to a Library Project, you need to add a "android.library.reference.N" line into the project.properties file of the ordinary project. For example, if my main project wants to point to two Library Projects, my project.properties file for the main project would include the following:
android.library.reference.1=../LibraryA
android.library.reference.2=../../LibraryB
where the ../ and the ../../ are the respective paths from the main project to the Library Projects (this is just an example). Note this list of references is 1-based and it should not contain gaps or duplicates. Google is well aware that this is not a perfect system but it was a reasonable solution that was compatible with Ant and Eclipse. Generally speaking, your IDE will attempt to maintain these files for you, but sometimes you may need to edit them by hand.
At first Library Projects did not support the following:
Library Projects pointing to other Library Projects
Library Projects containing aidl files
Library Projects containing assets folder
However subsequent sdk releases solved all of these problems.
For more information on Library Projects, see the official documentation.

Export the project as a JAR is not the right way to link a library project to your app project through Properties -> Java Build Path -> Library.
Neither it is to link the project as a required project through Properties -> Java Build Path -> Projects.
First of all, read the Library projects topic at Android developers -> Developing -> Managing projects: http://developer.android.com/guide/developing/projects/index.html#LibraryProjects
After this, read the Setting up a Library Project and Referencing a library project topics again at Android Developers -> Developing -> Managing projects -> From Eclipse With ADT
So... the steps are:
Create your Library project normally as a Android Project;
Set "is library" in the project properties -> Android Create your App
project normally;
Add a reference to your library in the project properties -> Android -> Add.
After this you can use all classes, components (activities, services, providers, receivers), resources etc.
Ex.: to reference any resources in a xml layout, for example, you should use #mylib:id/my_id or #mylib:layout/my_lib_layout
Obs.: If you use components of your library in app project, you must replicate them in your app manifest.

Also, I got the attributes working, but not in the way it should work I think.
You must use as the namespace in the element that uses your custom attributes, the namespace of your main app, not that of the library project. So, in your example, if you specify for the value of "xmlns:fnord" the namespace of your app project, it works.
Also, when reading the custom attributes in your custom PredicateLayout(Context,AttributeSet) constructor, you must specify the app's namespace as well in calls to attributes.getAttributeValue().
Which is a pain, since that code is in your library app which doesn't/shouldn't know about the app project it is used in. I worked around that by having the app call a static method ViewUtil.setAttributeNamespace(appNamespace) in my app's onCreate(), and the library's custom views use that namespace to retrieve the custom attributes. The attrs.xml file can then remain in the library project as well. Now the only ugly thing is that the layout XML must use the app's namespace on custom views, so you can't put those layout XML's in the library project.

Export your library project as a JAR and reference it in your application project's "Java Build Path" as a JAR.

The "Export your library as a jar" solution" only works if your library project contains source code only. In this case the OP's question mentions that his library project contains ui-related stuff.
We have the exact same issue on my team of wanting to have library projects that hold ui-related source and resources. We ended up overhauling our Ant build system in order to have applications engulf the library projects during build time. Unfortunately no solution of this sort seems to be compatible with Eclipse and this is a major source of frustration for the developers. We are still able to use Eclipse, but we have to jump through hoops to get it working and have to put up with diminished productivity.

Related

Passing properties to Android library project build file

I have an Android app project that is split into a free and a paid version. Everything that is common to both projects resides in an Android library project called "core". Then I have actual Android app projects for both the paid and the free version.
I'm using Ant scripts for building these two APKs. The paid version sets a property that tells the "core" project that the paid version is building. The free version tells the core project that the free version is building.
That used to work perfectly fine until Google decided to release ADT 22. Now the "core" project doesn't pick up these build properties anymore.
I suspect that library projects are built in a separate Ant build environment / process now.
So here's my question: how do I define properties for referenced Android library projects within an app project's build.xml file? How to pass over properties to these library project builds?
And where in the SDK's build.xml file are library projects actually compiled? I guess that would be the right spot to look into.
Thanks for your time.
EDIT for clarification
You have to create a modified copy of the original build.xml file from the Android SDK (see SDK-Folder/tools/ant) and also keep it up to date every now and again when Google releases an ADT update by merging the differences (and keeping the own modifications of course).
The build.xml file builds library projects using a <subant> task, which basically starts a separate build environment that does not automatically see any properties of the calling scope (which would be the app project's build environment).
However, within that subant tag you can export properties of the caller's scope to the library's build XML using a <propertyset> tag. Look for the following code block in your copy of build.xml and make a modification as shown below:
....
<echo level="info">Building Libraries with '${project.libraries.target}'...</echo>
<!-- no need to build the deps as we have already
the full list of libraries -->
<subant failonerror="true" buildpathref="project.library.folder.path" antfile="build.xml">
<!-- *** ADD THIS: *** -->
<propertyset id="project.library.buildargs">
<propertyref prefix="project.library.buildargs" />
</propertyset>
<target name="nodeps" />
<target name="${project.libraries.target}" />
<property name="emma.coverage.absolute.file" location="${out.absolute.dir}/coverage.em" />
</subant>
....
Above example makes all app project build.xml properties that are prefixed with project.library.buildargs. visible to all referenced Android library build scripts.
An alternative solution I have found to provide different values for my free version vs my paid version is to use [resources]. The Android build chain allows application projects to override the resource values set in the shared library project.
So for example, you can have a boolean resource in any XML file in res/values:
<bool name="paid_version">false</bool>
Of course, the paid version has the same resource in its own res/values subdirectory with a value of true.
Then from an Activity subclass or any other class with a Context, you can do the following:
if (getResources().getBoolean(R.id.paid_version)) {
// Do the paid version code here
}
This has the advantage that it is fairly easy to implement. On the down side, this is a run-time check based on dynamic code. This means that the code cannot be optimized away by the compiler or any other static analysis tool when the resource value is set to false.

Using Activities from Library projects

I have a Library project set up and a project which depends on this library project - Everything compiles fine and I've had the Dependent project running fine however;
I'm have an intermittent problem however while using an Activity from the Library project.
My Library project can be "unchecked" as a library project and the "picker" Activity can be run in isolation. Running the Library project in it's own right works fine with no problems.
When I use the Library project (and the "picker" Activity) from the dependent project it gives me either NullPointerExceptions (or historically DexOp) errors saying that the "picker" Activity can't find it's resources.
Can anybody tell me if they have experienced this before?
EDIT
Manually copying the layout.xml used by the Library project activity to the dependent project makes the project open the "picker" Activity correctly. Is this required?! Surely not? This further makes me wonder if there is a problem with merging/referencing the integer id's from R.java in the Library project.
EDIT
I'm not sure if this is of any consequence, but one of my Library projects is a wrapper around a set of custom views used in different front end projects.
These custom views each have an Activity so that they can be tested in isolation.
One of these view's has custom attributes, which while running in isolation work very well. However, it doesn't seem like the dependent project correctly pull's in the attributes and keep's them in their original namespace, causing the imported layout's to throw compilation errors:
[2012-05-16 12:07:28 - Project] D:\opt\workspace\CustomGlowList\res\layout\main.xml:14: error: No resource identifier found for attribute 'listId' in package 'com.company.library.glowlist'
[2012-05-16 12:07:28 - Project] D:\opt\workspace\CustomGlowList\res\layout\main.xml:14: error: No resource identifier found for attribute 'type' in package 'com.company.library.glowlist
EDIT
DexOp errors were solved by removing a duplicate file name which was present in the Dependent project. Not sure if the file name was the problem or the contents of the file.
EDIT
I've been unable to find a solution to this problem as of yet (although #yorkw's answer certainly helps with the xml attributes! Thanks).
I have managed to make this problem intermittent however:
I have gone through each of the library projects and ensured they all had their own namespace (ie, com.company.library.component1, com.company.library.component2 etc). After a couple of clean's (each project ordered with the correct precedence) this problem resolves itself, however does eventually come back when switching around library/not a library to test components.
Cause:
Issue 9656: Library projects don't support custom XML attributes for custom classes
Solution:
Upgrade to latest SDK & ADT version (fixed was released since r17) and use http://schemas.android.com/apk/res-auto as custom attributes' namespace URI, see Revisions for ADT 17.0.0:
Added support for custom views with custom attributes in libraries. Layouts using custom attributes must use the namespace URI http://schemas.android.com/apk/res-auto instead of the URI that includes the app package name. This URI is replaced with the app specific one at build time.
Related Topic:
Help with a custom View attributes inside a Android Library Project
not sure how you use the android library , but i've done this thing a lot of times without any problems , so please have a reading of the next things regarding using android libraries:
in order for an android project to use an android library project , you can either edit the "project.properties" and add the path to the library project there , or , much easier, right click the project (that uses the library project) , choose "android" category , and choose there "add" and choose the library project.
in order to make the android project to always open the android library project , also choose "java build path"->"projects" and choose the library project.
on the "project.properties" , try to set the target to the same target for both projects , and to the newest one that you have (latest now is 15) ,even if you can't test the app on this android version .
source files and all resources files (in the res folder) are ok to be used on the library projects.
assets folders cannot be used inside the library project . only on the android project that actually runs , the assets folder can be used . same thing goes to the proguard file .
the manifest of the library projects almost doesn't need to have almost anything . see this post for more information: https://stackoverflow.com/a/10445630/878126 . if there are activities on the library project that you wish to be able to access via the project that use it , don't forget to include them in the manifest of the android project (no need to write them in the manifest of the android library) .
remember to run lint before you export the app . it gives you plenty of warnings , but the most important warning is when you use too-new functions that cannot run on the range of APIs that you target . this is important for libraries since it's easy to get lost if there are multiple sources .
if you wish to extend activities on the android library , you need some kind of a method to go between them . the only way i know of is to extend the application and let it be the manager of how to create an intent for each of the activities . i think you can do other tricks , but they are all probably similar to this one.
if you have the same resource (any resource on the "res" folder) on both the android library and the android project, the one on the android project will replace the other one . this has advantages and disadvantages . remember that you can't have different file extensions for the same resource .
The problem was being caused by the R files from each of the Library projects not correctly being built and referenced. The resource files are built and referenced directly from the calling project.
Each of the Libraries need to have unique package as defined in the AndroidManifest.xml. This leads to each of it's resources being compiled in that unique namespace within the calling project alongside the Library jar which contains the class files.
The problem becomes intermittent when switching between a library and a runnable project because a clean and build needs to take place to regenerate these files as it isn't done automagically when unclicking the Use as library checkbox, where as the jar (and java classes) don't require as much coaxing for them to be correctly referenced as the library projects references them when acting as a Library.
This can lead to intermittent and also varying errors including missing references, DexOp and NullPointerExceptions depending on to what degree the R.java files have been mangled or partially built and what conflicts are taking places between packages.
I have same issue like, I have one library project and it has some activity.
When I was calling library project's Activity from my Main project, layout files resources were not getting loaded properly for the libray project's activity and giving "nullpointer exception" or "class could not be loaded", etc.
Solution: I have noticed that same layout file name is getting used in my Library project and Main project. I have just renamed those activity and it is solved.
May be this will help you.
I had similar issue when referencing Library project inside the Android App project. I deleted the R.java file from Library project so it generated again and App picked up the generated file. You should see the generated R.java file under your app project->gen->library_namespace_R.java.

Building an android project referencing android library project using ant / teamcity

I got a android project say project A ..now this project project A depends on a Android lib project say LibX. Now LibX depends on another android library project LibY. How can I build my project using ant.
Here is the android documentation I am referencing to -
http://developer.android.com/guide/developing/projects/projects-cmdline.html
Here's what it says
At build time, the libraries are merged with the application one at a time, starting from the lowest priority to the highest. Note that a library cannot itself reference another library and that, at build time, libraries are not merged with each other before being merged with the application.
Is there a way around this?
by Android Developer site: source in http://developer.android.com/tools/projects/index.html , section at Library Projects:
"... Structurally, a library project is similar to a standard Android
application project. For example, it includes a manifest file at the
project root, as well as src/, res/ and similar directories. The
project can contain the same types of source code and resources as a
standard Android project, stored in the same way. For example, source
code in the library project can access its own resources through its R
class.
However, a library project differs from a standard Android application
project in that you cannot compile it directly to its own .apk and run
it on an Android device. Similarly, you cannot export the library
project to a self-contained JAR file, as you would do for a true
library. Instead, you must compile the library indirectly, by
referencing the library in the dependent application and building that
application.
When you build an application that depends on a library project, the
SDK tools compile the library into a temporary JAR file and uses it in
the main project, then uses the result to generate the .apk. In cases
where a resource ID is defined in both the application and the
library, the tools ensure that the resource declared in the
application gets priority and that the resource in the library project
is not compiled into the application .apk. This gives your application
the flexibility to either use or redefine any resource behaviors or
values that are defined in any library.
To organize your code further, your application can add references to
multiple library projects, then specify the relative priority of the
resources in each library. This lets you build up the resources
actually used in your application in a cumulative manner. When two
libraries referenced from an application define the same resource ID,
the tools select the resource from the library with higher priority
and discard the other.
Once you have added references to library projects to your Android
project, you can set their relative priority. At build time, the
libraries are merged with the application one at a time, starting from
the lowest priority to the highest.
Library projects can reference other library projects and can import
an external library (JAR) in the normal way. ..."
I went through a similar problem when using the library Rajawali (version 0.9). There was a need to distribute a file. Single jar and applications would use this JAR to display 3D screens. The problem was that our library was a customization that used library resources Rajawali. So two project structures were created (such as library project). When generating. JAR application that used the resources did not work for the reasons you explain above), this because the library uses Rajawali features of images to be loaded with IDs that were not recognized in the version of the target application.
The solution of the single JAR can be validated by modifying the code to not use the Rajawali resources via R.raw.X (Android approach) to go to use the folder assets / , and make the component use Rajawali AsseptManager to open resources. The solution was exported JAR folder with the internal assets / and the bytecode (. Class) and our LIB Rajawali.
By Fat-JAR Eclipse PlugIn (or 0.0.31 +) [update site http://kuruczgrafika.de/fatjar] could generate a single JAR and use it in the target application. The ANT script was used to run the XML below and a JAR file was generated. The file "lib3d_NAME_HERE.jar" (.JAR) will be generated in the /build/lib3d_NAME_HERE.jar
<?xml version="1.0"?>
<project name="lib3d_NAME_HERE" default="main" basedir=".">
<property name="projectPath" value="D:\Development\lib3d_NAME_HERE"/>
<!-- this file was created by Fat-Jar Eclipse Plug-in -->
<!-- the ANT-Export is in a very early stage, so this -->
<!-- is only experimental, ANT 1.6 or above is -->
<!-- required, feedback is always welcome: -->
<!-- http://sourceforge.net/projects/fjep -->
<!-- uncomment the following lines if using ANT outside Eclipse -->
<!--
<property name="fjepPath" value="reference:file:plugins/net.sf.fjep.fatjar_0.0.31/fatjar.jar"/>
<taskdef name="fatjar.build" classname="net.sf.fjep.anttask.FJBuildTask" classpath="${fjepPath}"/>
<typedef name="fatjar.manifest" classname="net.sf.fjep.anttask.FJManifestType" classpath="${fjepPath}"/>
<typedef name="fatjar.exclude" classname="net.sf.fjep.anttask.FJExcludeType" classpath="${fjepPath}"/>
<typedef name="fatjar.jarsource" classname="net.sf.fjep.anttask.FJJarSourceType" classpath="${fjepPath}"/>
<typedef name="fatjar.filesource" classname="net.sf.fjep.anttask.FJFileSourceType" classpath="${fjepPath}"/>
-->
<!-- uncomment the above lines to use ANT outside of Eclipse -->
<target name="main">
<fatjar.build output="build/lib3d_NAME_HERE.jar">
<fatjar.manifest/>
<fatjar.filesource path="${projectPath}/bin/classes" relpath=""/>
<fatjar.filesource path="${projectPath}/assets/" relpath="assets"/>
</fatjar.build>
</target>
</project>

Android project as Jar Library

I am currently working on a Android Project where we are expected to merge our App with 2 more apps from vendors who wouldn't be sharing their code.So just wanted to know Is there any way we could just include there Source code as JAR Files in our project and then include their resources and point to them(I did do it using getResources().getIdentifier("splash", "layout", getPackageName()) But Its still not working ?? I think I have tried all possible methods so hoping you guys could help me with this.
To quote CommonsWare from this question:
Bear in mind that your packaged classes cannot reference resources (at
least not via R. syntax), and that JARs cannot package resources,
manifest entries, etc. If all you are trying to JAR up is pure Java
code (perhaps using Android APIs), then you should be fine.
Basically, you can only use JARs that contain pure java as libraries in your app, not entire other projects.
The Activities can be compiled into a jar and added to the main Android project and we need to add their project's resources into your Project. The only we could make it work is using the getResources().getIdentifier("splash", "layout", getPackageName()). Even the Widgets like TextView, Button and all those should be referred to using the getResources() method. Like, for example, If you want to perform a action on particular button then we need to identify them by getResources().getIdentifier("Button" /*id in the XML File*/, "id"/*type*/, getPackageName()).
One more thing: you need to specify all the Activities in your Main Android Project's AndroidManifest.xml file with their package name. I hope this solves something.
In order to support faster build times, the r16 tools are creating their own jar files inside of Android Library Projects. You can use this feature to solve this issue. If a vendor would like to release their Android Library Project but without source code, they can make a copy of that Android Library Project that contains everything except for the source code tree. Next, include the jar file from the original Android Library Porject (the one that the r16 tools built.) This will allow you to have a component you can distribute that does not require source code. The consumer of this new Android Library Project will need to manually add any necessary meta data to their own project's AndroidManifest.xml file as needed (Activities, Providers, Permissions, etc).

How make Android self components and use it from a jar library?

I'm trying to create an android component that can be easily added to android projects as a jar library.
For this, I had to create new xml attributes in "res/values/attr.xml" that I add to my graphic xml element using the path:
xmlns:app="http://schemas.android.com/apk/res/com.component.mypackage"
Then I import this project as a jar library into another project.
To create my graphic components in the new project, I must change the path below:
xmlns:app="http://schemas.android.com/apk/res/com.mylibrary"
But the path is incorrect: the custom attributes are not found.
I managed to integrate the R file in the library jar and I could access it from my xml to declare a custom component like this:
<PreferenceScreen
xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res/com.myLibraryPackage">
<com.myLibraryPackage.mySelfComponent
android:title="Name"
android:key="name"
app:hintText="Input your name"
android:dialogTitle="Your name "
app:validator="com.myLibraryPackage.myValidatorClass" />
What is strange is that if I put my file attr.xml in resources of my project, it works, which means it find com.myLibraryPackage.mySelfComponent. In that case, why it can't find also com.myLibraryPackage ?
(I also tried replacing
xmlns:app="http://schemas.android.com/apk/res/com.myLibraryPackage"
by
xmlns:app="http://schemas.android.com/apk/res/com.myApplicationPackage"
but it still doesn't work)
I would have preferred to use a jar to facilitate its integration in a project !
Has anyone encountered a problem like this who could help me?
Thank you.
I'm trying to create an android
component that can be easily added to
android projects as a jar library.
If you want reuse code and resources, it won't be possible to do it with a jar file. You'll need to convert your library to a library project.
Then I import this project as a jar
library into another project. To
create my graphic components in the
new project, I must change the path
below:
If you're using a library project, you'd still reference the custom attribute as if it were contained in the application (since android will merge all the resources together when the application is compiled):
xmlns:app="http://schemas.android.com/apk/res/com.component.mypackage"

Categories

Resources