How to use the new manifest merger (of Android Studio and Gradle)? - android
Background
In the past, when Eclipse&ADT were the official tools to develop for Android, you could simply use "manifestmerger.enabled=true" inside the "project.properties" of the app's project, and you got it merging all of the libraries' manifests automatically (and I've posted about it here).
This worked, sometimes. It had a lot of weird issues, and I always preferred to just avoid using it, and put what is needed into the main manifest file manually.
The problem
Somewhere on 2014, Google announced that the new Android-Studio (0.1 I think), together with Gradle, will allow you to choose exactly how to perform merging of libraries' components.
However, the new instructions (link here) are very complex and I really (really) tried to understand how to use them, and also didn't find samples of how to use them.
It's not that I didn't understand anything, but I'm not sure if I understood well.
What I've found
On the bright side, I've found out that merging is done completely automatically, so if you have a BroadcastReceiver on the library's manifest (and as a class, of course), it will be added to the app's project that uses it.
The question
I can't simply ask everything to be explained. I think it will be enough to ask those questions:
How can I choose which app components (permissions, activities,...) to be ignored from being auto-merged?
How can I point override app components (of the library) attributes (on the app's project) ? for example the theme of the activities?
Is there a way to completely disable the auto-merger for the manifest files?
What happens with manifests of dependencies that are inside repositories? Are they merged too?
Are there any tutorials/samples/videos regarding this new (well new for me) feature?
Are there any things I should be aware of when using the auto-merger?
I hope those questions are representative enough, informative enough, yet not too hard to answer for people who know.
1. Disabling elements
You can always explicitly disable permissions and features in your app's manifest and override any library values. And i found that you can disable elements from library.
Example
Consider the following code from the above link:
<activity-alias android:name="foo.bar.alias">
<meta-data
android:name="zoo"
tools:node="remove" />
</activity-alias>
By having this code inside your manifest you ensure that the merger finds any <activity-alias> elements with android:name="foo.bar.alias" attribute and removes a <meta-data> element if it has the android:name="zoo" attribute. It removes just the "zoo" meta data. Not the activity alias. If you specify this in your main manifest it will be effective on anything that has been merged so far (elements from libraries).
Example #2
Since you requested an example with activities, this is what I've come up with:
<activity android:name="com.example.ui.MyActivity" tools:node="remove" />
This line will make the merger remove any activities with android:name="com.example.ui.MyActivity" attribute that have been merged so far. So if you specify this in your main manifest it will effectively remove any com.example.ui.MyActivity entries that might have been merged from libraries.
2. Overriding attributes from library
The order in which the values are merged are described here. Basically, it goes like this: libraries, then main manifest, then flavors and build types manifests if you use those.
What are build types?
The default are "debug" and "release". You can define your own and override settings like signing or proguard. For your purposes you could say it's the equivalent of run configurations.
It works like this: you put your default and shared values inside the main manifest. Then in flavor manifests you override the values you need. Google "gradle flavors" for more info.
The following example is taken from a previous version of manifest merger documentation.
Override an attribute coming from a library
Using tools:replace="x, y, z" will override x,y,z attributes from the
imported library’s activity XML declarations.
Higher Priority declaration
<activity
android:name="com.foo.bar.ActivityOne"
android:screenOrientation="portrait"
android:theme="#theme1"
tools:replace="theme"/>
with a lower priority declaration :
<activity
android:name="com.foo.bar.ActivityOne"
android:theme="#olddogtheme"
android:windowSoftInputMode="stateUnchanged"
android:exported="true">
will result in :
<activity
android:name="com.foo.bar.ActivityOne"
android:screenOrientation="portrait"
android:theme="#theme1"
android:windowSoftInputMode="stateUnchanged"
android:exported="true"/>
3. Disabling manifest merger altogether
See Disable Manifest Merger in Android Gradle Build.
android.applicationVariants.all { variant ->
variant.processResources.manifestFile = file('src/main/AndroidManifest.xml')
variant.processManifest.enabled=false
}
In what file do you put this?
At the end of your module's (not root project) build.gradle.
4. Are manifests from dependencies merged?
Yes they are (they're libraries).
Is there a way to block merging certain library manifests?
Not that I know of, sorry.
5. Any tutorials?
Depends on what are you trying to achive. So far it always worked for me out-of-the-box.
e.g. http://www.myandroidsolutions.com/2014/04/10/android-gradle-manifest-merge/
The manifest merger documentation (link below).
I don't know about any videos.
6. Anything I should be aware of?
You can check the generated manifest if you get suspicious about extra permissions etc. It's located in project/module/build/intermediates/manifests/full/[flavor]/build-type/AndroidManifest.xml.
Source: https://developer.android.com/studio/build/manifest-merge
Some of the links in this thread are obsolete. Here's the main one that is updated related to auto merger of manifests, by gradle, for Android AARs.
https://developer.android.com/studio/build/manifest-merge
Related
Automatically merge meta-data resources from libraries
I'm the developer of a library that makes use of APP_RESTRICTIONS. Till now I had the following configuration in the AndroidManifest.xml: <meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="#xml/library_restrictions" /> However, one of our customers now contacted us because his build was failing after adding our library. It turns out that he uses another library which also provides APP_RESTRICTIONS. I know that I can use tools:node="replace" or tools:node="merge" however this basically means that just one of the restriction configurations get active since it is an attribute on the meta-data. What I need is the content of the two resource files merged automatically to guarantee that the configuration field shows up in the MDM solution. Does anyone know a solution other than informing the developer in the readme that he has to manually merge the content of these two files?
android: allow creation of an activity-alias whose targetActivity is in an aar/sdk
I'm writing an SDK and would like developers to be able to create an activity-alias whose targetActivity is set to an activity inside my SDK. I'm doing this because I'd like them to be able to customize the intent filter on a specific activity in the SDK. If in the sdk's manifest there is ActivityX, I'd like them to be able to write an activity-alias like this in their app's manifest: <activity-alias android:name="abc" android:targetActivity="ActivityX"> <intent-filter> ... user's custom intent filter </intent-filter> </activity-alias> The problem I'm coming across is that the targetActivity has the restriction that it: "... must match the name attribute of an activity element that precedes the alias in the manifest." This is a problem because no matter where I place the activity in the sdk's manifest or where I place the alias in an example app's manifest, the alias always comes before the activity in the final merged manifest causing an INSTALL_PARSE_FAILED_MANIFEST_MALFORMED error. One idea is to put an alias without an intent filter just after ActivityX is declared in the sdk manifest and hope that the two aliases will be merged together and stay in the sdk alias's position. But I can't figure out how to do that. One reason that might not be working is that two aliases may not be able to conflict. Do you have thoughts on solving this via a merge solution or some other technique?
An identical issue was brought up in the AOSP. A workaround to the problem is described there as follows: Manually include the manifest entry for the Activity from [the sdk] in the manifest of the application project, placing it before the activity-alias entry. Despite the fact that this workaround has the problem of ... duplicate code across manifests. it seems that the project maintainers deemed this solution as adequate. There is no indication that a fix to the underlying problem will be released any time soon.
2 Manifests with 2 application tags
I have a project with a product flavor that uses a different activity than the main code. I had to define that new activity in a second Manifest file, but I still want to use the original main Manifest as well. But with 2 Manifests with 2 application tags, I get 2 instances of the app installed on the device. Is there a way I can make this work, or will I just have to copy/paste the whole original Manifest and take out the link to it?
I would refactor to an Android library, where all common stuff is located inclusively the manifest. And an app that includes this library as dependency with its own manifest. When building the app the manifest merger should pick up the manifest from the library and merge it with the manifest of the app. The library could also implement both flavors.
Clean up unused Android permissions
If I wanted to research how and where permissions [requested in the Mainfest.xml] were used in an Android app for the purposes of removing them is there an easy way of doing this? Does lint or findbugs offer some sort of support for tracking permissions used/abused in a project?
I came from the future to save your lives. Here (in the future), LINT does check for missing permissions as you can see on LINT checks. So, go to your AndroidManifest.xml and remove all tags <uses-permission> using Android permissions (meaning, don't delete permissions that belong to your app, such as UA_DATA and C2D_MESSAGE). Then run LINT analysis. Click on Analyze then Inspect Code... Look under Android -> Constant and Resource Type Mismatches You should see all missing permissions. Then you can just right-click them and select Apply fix "Add Permission". If you select this option, Android Studio will include one permission for every error. So you'll end up with multiple copies of the same permission on your Manifest file, just delete the duplicates. You can do it manually too. Here is the description of the LINT rule: ID ResourceType Description This inspection looks at Android API calls that have been annotated with various support annotations (such as RequiresPermission or UiThread) and flags any calls that are not using the API correctly as specified by the annotations. Examples of errors flagged by this inspection: Passing the wrong type of resource integer (such as R.string) to an API that expects a different type (such as R.dimen). Forgetting to invoke the overridden method (via super) in methods that require it Calling a method that requires a permission without having declared that permission in the manifest Passing a resource color reference to a method which expects an RGB integer value. ...and many more. For more information, see the documentation at http://developer.android.com/tools/debugging/annotations.html I'm using Android Studio 2.1.2.
In your app manifest file you should have a tab "Merged Manifest" there you can see your final manifest and the permissions you request you can click on a permission to see where it came from. (who added it - ex': sdk or what code it came from) There is also a simple way to remove a permission by adding to manifest: <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" /> Also remember to add the tools at the top: <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="...">
The way I would do it for an app for which I didn't write the code would be to remove the permissions one by one and test the app end-to-end each time. When it fails, narrow it down. If not, that permission may not be used.
You will have to try removing them one by one and checking i fthe app still works OK. This is not checked by lint in any way (it should be). When they come back (they are currently down), you can upload your apk to this website (if that's ok with you) and let them statically analyse the permissions you are using: http://www.android-permissions.org/
Best way is to understand what the may actually do. If it is ever going to use the camera then you know you need the camera permission.
Or you could just learn what your app does and then go through the permissions and see which ones are extra. What does your app do, what phone features does it use. There should be some documentation somewhere on what it should do and what methods are in there
Is it possible to export library's manifest (permissions, activities)
I have created a library module that is working when I add the permissions and activity tags to every project's manifest that uses it. I'd like to encapsulate it as much as possible, is there any support for exporting a library's manifest tags so that I, and others can skip this step? http://developer.android.com/tools/projects/projects-eclipse.html#ReferencingLibraryProject alludes to 'no'.
Have you tried setting the manifestmerger property to true. See this question.