How to Keep Placeholders in an AAR's Manifest? - android

I'm building an AAR library for Android and need to include a ContentProvider in the library's manifest, as such:
<provider
android:name="sdk.example.Preferences"
android:authorities="${applicationId}.preferences"
android:exported="false"
/>
The problem is that when the AAR is built, ${applicationId} is replaced by the AAR's package. What I want is for the manifest of the final AAR to keep ${applicationId} so that it can be replaced with the main application's package when it itself is built. Any idea how to do this?
Currently I'm editing the AAR manually to achieve this, but want to find a better solution

Well - the first approach that comes to mind is to use a resource for the authority name, but this is not possible - Using #string for android:authorities in a ContentProvider.
There is however a Maven job that replaces the authority, but I have no idea how it behaves when AAR libraries are involved - Android Manifest with #String reference - specifically android:authorities.
Please report your solution.

This is now done automatically in Android Studio 2.0

Related

Android - How should you manage multiple modules? Manifests, grades, etc.

I understand this question is vague, but can someone outline the rules and/or how we should be dealing with multiple modules?
I've been trying to separate my app out into a base feature module, application module and instant app module.
However I've been having a nightmare building it.
I've tried searching online but there isn't really much documentation in it?
Ive got two activities in my base module manifest, as I want these in both my installed and instant app. Do I then need to copy these activity manifest entries into my other manifests? I tried running my installed apk without adding in these activities (I thought it might pull it from the base module) but then android studio says can't find default activity to launch the application with. So I need to copy the activity entries into all manifests?
I've also got manifest entry conflicts from all the libraries I'm using. FacebookInitProvider , FacebookInitProvider, CrashlyticsInitProvider etc. I don't have these entries in any manifest, they are adding themselves in to every manifest causing merge conflicts when building.
With the build grades, I've put in the base just the libraries necessary to run the base / instant app (to keep it as small as possible). The installed gradle then has all the extra libraries for the full sized application. If I use
implementation project(":base")
Will it automatically pull in all the dependencies that base uses? Or do I need to redeclare these?
I ask because after getting the app to build, firebase and firestore was causing an exception on getting the instance with the message "Firestore module not found" which makes it look like it hasn't pulled in the dependencies properly?
I apologise for the lengthy post, but I'm honestly at the end of my tether here. Truly stuck!
Im not sure I understand all your project structure correctly so I will give you general information on an app with modules:
Lets say you have the application called "appone" and have a module called "moduleone"
In the module gradle file you declare the minimum you need for the module to work properly by itself and in the manifest just configuration specific for the module that will not be required to be defined in the appone manifest.
Now in the appone manifest, this is the main file, you will have to set here the activity declarations and app permissions (not in moduleone), android studio merges the two files automatically so when you compile it will make one manifest file with both manifests contents so this is what can make conflicts if you declare the same or conflicting data on both files.
In the appone build.gradle file this is where you declare the implementation project(':moduleone'), and the implementation of libraries required by appone.
If for example moduleone uses firebase library and in appone you also directly require access to the firebase library you could declare it in both build.gradle files, you just need to make sure both use the same version.
Also you will need to declare moduleone on the settings.gradle file using: include ':moduleone'
appone is declared as an com.android.application and moduleone is declared as com.android.library.
Also appone has in its manifest an activity declared with the LAUNCHER category.

Android manifestmerger.enabled does not work for sharedUserId

In my Android library manifest file I have set sharedUserId property.
I have referenced to this lib project in my app1 and app2.
I have added manifestmerger.enabled=true to project.properties files of both apps.
However sharedUserId does not work (note: it works ok if I set thisproperty to app manifest file directly).
While looking app/bin/AndroidManifest I dont see this property - so looks like merge didn't happen.
I am using Eclipse ADT build22.3.0
Any idea what is the problem?
Basically what I want is to have ability to expose propery from my jar library.
This is not intended to work.
From the inline documentation of the ManifestMerger class
- root manifest: attributes ignored, warn if defined.
The Android Manifest documentation lists android:sharedUserId under the root element of the Manifest file, so it will be in the group of things which cannot be merged in from a library.
You may of course have additional issues preventing merging from working in general but even after those are corrected it should not work for sharedUserId (and other root level attributes) in specific.

Applications manifest and librarys manifest in Android

I'm developing an application, with another project as my library.
What properties are merged in the manifest files?
Example - If the permissions are already specified in the Library's manifest file, do they need to be specified again in the applications manifest?
Also, if there is a service in the Library project, do I need to specify again manually in the Applications manifest too (additional to library's manifest).
Thanks
There is a section of this page: http://developer.android.com/tools/projects/projects-eclipse.html#SettingUpLibraryProject that says you must (re)declare all of the bits of the library project that your application will be using in the manifest file.
Declaring library components in the manifest file
In the manifest file of the application project, you must add
declarations of all components that the application will use that are
imported from a library project. For example, you must declare activity, service, receiver, provider, and so on, as well as permission, uses-library, and similar elements.
Declarations should reference the library components by their
fully-qualified package names, where appropriate.
Personally, this seems redundant, but it may be because the app doesn't need to use all of the components of the library project, and the app shouldn't assume it will.

Android Library Manifest vs. App Manifest

I've read similar questions here, but am still not clear on a couple of things. Using a Library Project means that my overall project will have two manifests -- one for the library and the other for the "main" app project -- and I'm not clear what goes in which or if there is some redundancy.
I'm developing an app widget with "lite" and "paid" versions, so will have almost all code in a library project. Being a widget, the library will have at least a receiver, a service, a configuration activity, plus a couple of other activities. So where should the full declarations of these components -- including intents, filters, etc. -- be declared? Do they go in the manifest for the library, or in the manifest for the application package itself, referencing the classes in the library (e.g. android:name="com.foo.mylibrary.MyService")?
Some examples I've looked at seem to declare them in both manifests, but I suspect that putting these in one or the other is a no-op.
Using a Library Project means that my overall project will have two manifests -- one for the library and the other for the "main" app project -- and I'm not clear what goes in which or if there is some redundancy.
The library project manifest is not presently used.
Gradle for Android, and therefore Android Studio, support library projects and AARs publishing a manifest. This can include things like activity declarations, required permissions or features, or minimum supported Android SDK levels.
The rules for how library manifests are merged with the app's own manifest -- particularly when you take build types and product flavors into account -- is a bit complex.
So where should the full declarations of these components -- including intents, filters, etc. -- be declared?
In the host project.
The library could publish those components, and the Android Studio host project can then remove them if needed.
Do they go in the manifest for the library, or in the manifest for the application package itself, referencing the classes in the library (e.g. android:name="com.foo.mylibrary.MyService")?
The latter.
In either (with Gradle for Android and Android Studio). In theory, it is easier for the library to publish the components, so the app author does not have to. Personally, I am not a huge fan of this, as too many developers will wind up shipping unnecessary manifest entries.
As of ADT r20 Preview 3 it is now possible to merge manifests. So common configuration can now be put into the library manifest. See https://stackoverflow.com/a/10400355/262789 for more information.
Version 13 of Intellij IDEA is necessary for manifest merging support (manifestmerger.enabled=true). Also the Grade based build system appears to be necessary for Android Studio support.
Any referenced android elements like activities, receivers, services, etc. MUST go into your Application manifest or they won't be recognized by the OS. As you guessed, the Library manifest file is pretty much an empty implementation
UPDATE
As CommonsWare points out above, the Android build tools will now attempt to merge the various manifests on your behalf. Leaving up the original answer for posterity

Specifying Android project dependencies (in Eclipse)

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.

Categories

Resources