com.android.manifmerger
Class ManifestMerger

java.lang.Object
  extended by com.android.manifmerger.ManifestMerger

public class ManifestMerger
extends java.lang.Object

Merges a library manifest into a main application manifest.

To use, create with ManifestMerger(IMergerLog, ICallback) then call process(File, File, File[], Map, String).

 Merge operations:
 - root manifest: attributes ignored, warn if defined.
 - application:
      G- @attributes: most attributes are ignored in libs
          except: application:name if defined, it must match.
          except: application:agentBackup if defined, it must match.
          (these represent class names and we don't want a lib to assume their app or backup
           classes are being used when that will never be the case.)
      C- activity / activity-alias / service / receiver / provider
          => Merge as-is. Error if exists in the destination (same @name)
             unless the definitions are exactly the same.
             New elements are always merged at the end of the application element.
          => Indicate if there's a dup.
      D- uses-library
          => Merge. OK if already exists same @name.
          => Merge @required: true>false.
      C- meta-data
          => Merge as-is. Error if exists in the destination (same @name)
             unless the definitions are exactly the same.
             New elements are always merged at the end of the application element.
          => Indicate if there's a dup.
 A- instrumentation:
      => Do not merge. ignore the ones from libs.
 C- permission / permission-group / permission-tree:
      => Merge as-is. Error if exists in the destination (same @name)
         unless the definitions are exactly the same.
 C- uses-permission:
      => Add. OK if already defined.
 E- uses-sdk:
      @minSdkVersion: error if dest<lib. Never automatically change dest minsdk.
                              Codenames are accepted if we can resolve their API level.
      @targetSdkVersion: warning if dest<lib.
                                 Never automatically change dest targetsdk.
      @maxSdkVersion: obsolete, ignored. Not used in comparisons and not merged.
 D- uses-feature with @name:
      => Merge with same @name
      => Merge @required: true>false.
      - Do not merge any @glEsVersion attribute at this point.
 F- uses-feature with @glEsVersion:
      => Error if defined in lib+dest with dest<lib. Never automatically change dest.
 B- uses-configuration:
      => There can be many. Error if source defines one that is not an exact match in dest.
      (e.g. right now app must manually define something that matches exactly each lib)
 B- supports-screens / compatible-screens:
      => Do not merge.
      => Error (warn?) if defined in lib and not strictly the same as in dest.
 B- supports-gl-texture:
      => Do not merge. Can have more than one.
      => Error (warn?) if defined in lib and not present as-is in dest.

 Strategies:
 A = Ignore, do not merge (no-op).
 B = Do not merge but if defined in both must match equally.
 C = Must not exist in dest or be exactly the same (key is the @name attribute).
 D = Add new or merge with same key @name, adjust @required true>false.
 E, F, G = Custom strategies; see above.

 What happens when merging libraries with conflicting information?
 Say for example a main manifest has a minSdkVersion of 3, whereas libraries have
 a minSdkVersion of 4 and 11. We could have 2 point of views:
 - Play it safe: If we have a library with a minSdkVersion of 11, it means this
   library code knows it can't work reliably on a lower API level. So the safest end
   result would be a merged manifest with the highest minSdkVersion of all libraries.
 - Trust the main manifest: When an app declares a given minSdkVersion, it also expects
   to run a given range of devices. If we change the final minSdkVersion, the app won't
   be available on as many devices as the developer might expect. And as a counterpoint
   to issue 1, the app may be careful and not call the library without checking the
   necessary features or APIs are available before hand.
 Both points of views are conflicting. The solution taken here is to be conservative
 and generate an error rather than merge and change a value that might be surprising.
 On the other hand this can be problematic and force a developer to keep the main
 manifest in sync with the libraries ones, in essence reducing the usefulness of the
 automated merge to pure trivial cases. The idea is to just start this way and enhance
 or revisit the mechanism later.
 


Constructor Summary
ManifestMerger(IMergerLog log, ICallback callback)
          Creates a new ManifestMerger.
 
Method Summary
 boolean isInsertSourceMarkers()
          Returns whether this manifest merger will insert source markers into the merged source
 boolean process(org.w3c.dom.Document mainDoc, org.w3c.dom.Document... libraryDocs)
          Performs the merge operation in-place in the given DOM.
 boolean process(org.w3c.dom.Document mainDoc, java.io.File[] libraryFiles, java.util.Map<java.lang.String,java.lang.String> injectAttributes, java.lang.String packageOverride)
          Performs the merge operation in-place in the given DOM.
 boolean process(java.io.File outputFile, java.io.File mainFile, java.io.File[] libraryFiles, java.util.Map<java.lang.String,java.lang.String> injectAttributes, java.lang.String packageOverride)
          Performs the merge operation.
 ManifestMerger setExtractPackagePrefix(boolean extract)
          Sets whether the manifest merger should extract package prefixes.
 void setInsertSourceMarkers(boolean insertSourceMarkers)
          Sets whether this manifest merger will insert source markers into the merged source
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ManifestMerger

public ManifestMerger(@NonNull
                      IMergerLog log,
                      @Nullable
                      ICallback callback)
Creates a new ManifestMerger.

Parameters:
log - A non-null merger log to capture all warnings, errors and their location.
callback - An optional callback that the merger can use to query the calling SDK.
Method Detail

setExtractPackagePrefix

public ManifestMerger setExtractPackagePrefix(boolean extract)
Sets whether the manifest merger should extract package prefixes.

When true, the merged document is revisited and class names attributes are shortened when possible, e.g. the package prefix is removed from the class name if it matches.

Parameters:
extract - If true, extract package prefixes.
Returns:
this, for constructor chaining

process

public boolean process(java.io.File outputFile,
                       java.io.File mainFile,
                       java.io.File[] libraryFiles,
                       java.util.Map<java.lang.String,java.lang.String> injectAttributes,
                       java.lang.String packageOverride)
Performs the merge operation.

This does NOT stop on errors, in an attempt to accumulate as much info as possible to return to the user. Unless it failed to read the main manifest, a result file will be created. However if process() returns false, the file should not be used except for debugging purposes.

Parameters:
outputFile - The output path to generate. Can be the same as the main path.
mainFile - The main manifest paths to read. What we merge into.
libraryFiles - The library manifest paths to read. Must not be null.
injectAttributes - A map of attributes to inject in the form [pseudo-xpath] => value. The key is "/manifest/elements...|attribute-ns-uri attribute-local-name", for example "/manifest/uses-sdk|http://schemas.android.com/apk/res/android minSdkVersion". (note the space separator between the attribute URI and its local name.) The elements will be created if they don't exists. Existing attributes will be modified. The replacement is done on the main document before merging.
packageOverride - an optional package override. This only affects the package attribute, all components (activities, receivers, etc...) are not affected by this.
Returns:
True if the merge was completed, false otherwise.

process

public boolean process(org.w3c.dom.Document mainDoc,
                       java.io.File[] libraryFiles,
                       java.util.Map<java.lang.String,java.lang.String> injectAttributes,
                       java.lang.String packageOverride)
Performs the merge operation in-place in the given DOM.

This does NOT stop on errors, in an attempt to accumulate as much info as possible to return to the user.

The method might modify the input XML document in-place for its own processing.

Parameters:
mainDoc - The document to merge into. Will be modified in-place.
libraryFiles - The library manifest paths to read. Must not be null. These will be modified in-place.
injectAttributes - A map of attributes to inject in the form [pseudo-xpath] => value. The key is "/manifest/elements...|attribute-ns-uri attribute-local-name", for example "/manifest/uses-sdk|http://schemas.android.com/apk/res/android minSdkVersion". (note the space separator between the attribute URI and its local name.) The elements will be created if they don't exists. Existing attributes will be modified. The replacement is done on the main document before merging.
packageOverride - an optional package override. This only affects the package attribute, all components (activities, receivers, etc...) are not affected by this.
Returns:
True on success, false if any error occurred (printed to the IMergerLog).

process

public boolean process(@NonNull
                       org.w3c.dom.Document mainDoc,
                       @NonNull
                       org.w3c.dom.Document... libraryDocs)
Performs the merge operation in-place in the given DOM.

This does NOT stop on errors, in an attempt to accumulate as much info as possible to return to the user.

The method might modify the input XML documents in-place for its own processing.

Parameters:
mainDoc - The document to merge into. Will be modified in-place.
libraryDocs - The library manifest documents to merge in. Must not be null. These will be modified in-place.
Returns:
True on success, false if any error occurred (printed to the IMergerLog).

setInsertSourceMarkers

public void setInsertSourceMarkers(boolean insertSourceMarkers)
Sets whether this manifest merger will insert source markers into the merged source

Parameters:
insertSourceMarkers - if true, insert source markers

isInsertSourceMarkers

public boolean isInsertSourceMarkers()
Returns whether this manifest merger will insert source markers into the merged source

Returns:
whether this manifest merger will insert source markers into the merged source