INSTALL_FAILED_DUPLICATE_PERMISSION には、${applicationId}

# Errorの原因

複数のflavorを利用して、違うパッケージのアプリをinstallしようとすると `INSTALL_FAILED_DUPLICATE_PERMISSION` とエラーが出て失敗する時がある。

```:text
com.android.ddmlib.InstallException: Failed to finalize session : INSTALL_FAILED_DUPLICATE_PERMISSION: Package me.mattak.example.develop attempting to redeclare permission me.mattak.example.permission.C2D_MESSAGE already owned by me.mattak.example
	at com.android.ddmlib.Device.installPackages(Device.java:888)
	at com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:101)
	at com.android.builder.testing.ConnectedDevice$installPackages$3.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
	at com.android.build.gradle.internal.tasks.InstallVariantTask.install(InstallVariantTask.groovy:91)
```

典型的なのはpush通知を利用している場合。

このようなbuildTypesでpackage名を分けていて、

```gradle:build.gradle
android {
    ...
    buildTypes {
        develop {
            applicationIdSuffix ".develop"
            signingConfig signingConfigs.develop
        }
        product {
            signingConfig signingConfigs.release
        }
    ...
    }
}
```

AndroidManifest.xml のpermissionにパッケージ名をダイレクトに記述していると、
Nexus 5 (kitkat) などでInstall時にエラーが起きる。

```xml:AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.mattak.example">

    ....

    <permission
        android:name="me.mattak.example.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="me.mattak.example.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <application
        android:name="me.mattak.example"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
    ...
    </application>
</manifest>
```

errorが起きるのはAndroidManifest内に定義している、permissionタグのパッケージ名がかぶっているから。

# PlaceHolderの利用

このエラーは `manifestPlaceHolders` を利用することで容易に回避できる。

```gradle
defaultConfigs {
    manifestPlaceholders = [appName:"@string/app_name_staging"]
}
```

本来であれば、このように利用する変数を事前に定義した上でAndroidManifest.xml内で

```xml:AndroidManifest.xml
<activity
    android:name="me.mattak.example.MainActivity"
    android:label="${appName}"
    android:screenOrientation="portrait">
</activity>
```

groovyのSimpleTemplateEngineのような埋め込みをおこなう必要がある。

ただapplicationIdは事前にtemplate内で展開される変数として定義されているため、
特になにも定義する事なく `${applicationId}` を利用して permissionを置き換えればいい。

```xml:AndroidManifest.xml
<permission
    android:name="${applicationId}.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
```

# 参考

- [Build Variantsで開発版Androidアプリを分ける](http://ninjinkun.hatenablog.com/entry/2014/08/18/102849)
- [Placeholder support](http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger#TOC-Placeholder-support)