3
votes

I want to use the Maven Resources Filtering plugin to externally define sensitive configuration data for an Android project. Therefore I created a .properties file which contains the sensitive data. It is excluded from version control.

# /.app_config.properties
# Application configuration
#
# Do not add this file to source control.
# The values are read and inserted into source files by Maven.

google.maps.v2.api.key = abc123
api.base.url = https://example.com/api

In the Android project I manage all sensitve data in a separate .xml file:

<!-- /res/values/app_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>    
  <string name="config_google_maps_v2_api_key">ENTER_YOUR_GOOGLE_MAPS_V2_API_KEY_HERE</string>
  <string name="config_base_url">ENTER_YOUR_SERVER_URL_HERE</string>
</resources>

For Maven I created another .xml file which tells which strings should be substituted when the .apk is built:

<!-- /filteres-res/app_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>    
  <string name="config_google_maps_v2_api_key">${google.maps.v2.api.key}</string>
  <string name="config_base_url">${api.base.url}</string>
</resources>

Here are the relevant parts of the pom.xml for Maven Filtering:

<!-- /pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <!-- Sure there is more configuration here -->

  <build>
    <finalName>${project.artifactId}</finalName>
    <sourceDirectory>src</sourceDirectory>
    <filters>
      <filter>${project.basedir}/.app_config.properties</filter>
    </filters>
    <resources>
      <resource>
        <directory>${project.basedir}/filtered-res</directory>
        <filtering>true</filtering>
        <targetPath>${project.basedir}/res/values/</targetPath>
        <includes>
          <include>**/*.xml</include>
        </includes>
      </resource>
      <resource>
        <directory>${project.basedir}/filtered-res</directory>
        <filtering>false</filtering>
        <excludes>
          <exclude>**/*.xml</exclude>
        </excludes>
      </resource>
    </resources>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>com.jayway.maven.plugins.android.generation2</groupId>
          <artifactId>android-maven-plugin</artifactId>
          <version>${android-maven-plugin.version}</version>
          <extensions>true</extensions>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>${maven-compiler-plugin.version}</version>
          <configuration>
            <compilerArgument>-Xlint:deprecation</compilerArgument>
            <!-- <resourceDirectory>${project.build.directory}/filtered-res</resourceDirectory> -->
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
        <artifactId>android-maven-plugin</artifactId>
        <configuration>
          <sdk>
            <platform>${sdk.platform}</platform>
          </sdk>
          <undeployBeforeDeploy>true</undeployBeforeDeploy>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>${maven-resources-plugin.version}</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>resources</goal>
            </goals>
          </execution>
          <execution>
            <id>default-resources</id>
            <phase>DISABLED</phase>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

The problem is the sensitive data is actually written to /res/values/app_config.xml instead of to the build only. This is what the file looks like after a build:

<!-- /res/values/app_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>    
  <string name="config_google_maps_v2_api_key">abc123</string>
  <string name="config_base_url">https://example.com/api</string>
</resources>
2

2 Answers

2
votes

The described effect is is created by the targetPath in your resource specification, which filters the source file and overwrites it afterwards.

The following both configurations will copy the filtered ressource in the build folder:

<resources>
  <resource>
    ...
    <!-- following defines a replacement target in the source part -->
    <targetPath>${project.basedir}/res/values/</targetPath>
    ...
</resource>

or you define it properly

<resources>
  <resource>
    ...
    <targetPath>${project.build.directory}/res/values/</targetPath>
    ...
</resource>

But this will not create a proper apk since com.jayway.maven.plugins.android.generation2:android-maven-plugin will not use the files in the build folder.

As a conclusion we can say, there is no way using resource filter and com.jayway.maven.plugins.android.generation2:android-maven-plugin. May be replacing the xml files in a created unsigned apk will work or your replace the xml file after the build with original.

0
votes

In the Android Maven plugin you can set from where should it read the resource files, so in your pom you will have something like:

  <plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>android-maven-plugin</artifactId>
    <configuration>
      <sdk>
        <platform>${sdk.platform}</platform>
      </sdk>
      <undeployBeforeDeploy>true</undeployBeforeDeploy>
      <resourceDirectory>${project.build.directory}/res</resourceDirectory>
    </configuration>
  </plugin>

and:

 <resources>
   <resource>
     ...
     <targetPath>${project.build.directory}/res</targetPath>
     ...
 </resource>

Link: android-maven-plugin and resource filtering

Hope this helps.