Errorの原因
複数のflavorを利用して、違うパッケージのアプリをinstallしようとすると INSTALL_FAILED_DUPLICATE_PERMISSION
とエラーが出て失敗する時がある。
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名を分けていて、
android {
...
buildTypes {
develop {
applicationIdSuffix ".develop"
signingConfig signingConfigs.develop
}
product {
signingConfig signingConfigs.release
}
...
}
}
AndroidManifest.xml のpermissionにパッケージ名をダイレクトに記述していると、
Nexus 5 (kitkat) などでInstall時にエラーが起きる。
<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
を利用することで容易に回避できる。
defaultConfigs {
manifestPlaceholders = [appName:"@string/app_name_staging"]
}
本来であれば、このように利用する変数を事前に定義した上でAndroidManifest.xml内で
<activity
android:name="me.mattak.example.MainActivity"
android:label="${appName}"
android:screenOrientation="portrait">
</activity>
groovyのSimpleTemplateEngineのような埋め込みをおこなう必要がある。
ただapplicationIdは事前にtemplate内で展開される変数として定義されているため、
特になにも定義する事なく ${applicationId}
を利用して permissionを置き換えればいい。
<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" />