Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Gradle: Install all build types on one device

How do I configure my project to be able to install the debug version alongside the release version when using GCM, ContentProvider, AccountType? (without the use of flavors)

I keep getting errors such as: INSTALL_FAILED_CONFLICTING_PROVIDER or INSTALL_FAILED_DUPLICATE_PERMISSION

like image 724
Benoit Avatar asked Feb 09 '23 18:02

Benoit


1 Answers

Installing a debug apk and the release apk on the same device is tricky if you are only using build types and not flavors (Why Build types and not flavors)

Most blog post are either outdated (talking about packageName) or force you to use flavors because the solution they propose does not support applicationIdSuffix and a build type cannot declare applicationId therefore you need to use a flavors

The solution I propose uses

  • an authority per build type
  • an account type per build type
  • a GCM permission per build type

For this to work I use applicationIdSuffix, manifest placeholders, BuildConfigField and resValue in the Gradle file.

The only problem left is when you want to have a different name for app and per language the string is not set as translatable (bug aosp tracker) This forces you to set abortOnError false otherwise you won't be able to make a release build.

build.gradle

project.ext {
    defaultApplicationId = "com.myapp.package"
}
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId defaultApplicationId

        manifestPlaceholders = [ applicationIdWithSuffix: "${applicationId}" ]

        buildConfigField "String", "ACCOUNT_TYPE", "\"${applicationId}\""
        buildConfigField "String", "AUTHORITY", "\"${applicationId}.provider\""

        resValue "string", "account_type", "${applicationId}"
        resValue "string", "authority", "${applicationId}.provider"
    }
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
            debuggable true

            manifestPlaceholders = [ applicationIdWithSuffix: defaultApplicationId + ".debug" ]

            buildConfigField "String", "ACCOUNT_TYPE",  "\"${defaultApplicationId}.debug\""
            buildConfigField "String", "AUTHORITY", "\"${defaultApplicationId}.debug.provider\""

            resValue "string", "account_type", "${defaultApplicationId}.debug"
            resValue "string", "authority", "${defaultApplicationId}.debug.provider"
        }
    }
    lintOptions {
        abortOnError false
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mypackage" >

    <permission
        android:name="${applicationIdWithSuffix}.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="${applicationIdWithSuffix}.permission.C2D_MESSAGE" />

    <application
        android:label="@string/app_name" >

        <provider
            android:name=".MyContentProvider"
            android:authorities="${applicationIdWithSuffix}.provider"
            android:exported="false"
            android:multiprocess="true" />
    </application>
</manifest>

Sync adapter xml

<sync-adapter
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:contentAuthority="@string/authority"
    android:accountType="@string/account_type"/>

Account authenticator

<account-authenticator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="@string/account_type"
    .../>

ContentProvider

I have a constant for Authority which takes it from the BuildConfig.

AUTHORITY = BuildConfig.AUTHORITY

Account type

To get the account type you take it from the BuildConfig too.

BuildConfig.ACCOUNT_TYPE

Multi language app name

If you want different names per app & language:

debug/values-en/strings.xml

<resources>
    <string name="app_name">MyApp debug EN</string>
</resources>

debug/values-fr/strings.xml

<resources>
    <string name="app_name">MyApp debug FR</string>
</resources>

main/values-en/strings.xml

<resources>
    <string name="app_name">MyApp EN</string>
</resources>

main/values-fr/strings.xml

<resources>
    <string name="app_name">MyApp FR</string>
</resources>
like image 180
Benoit Avatar answered Feb 11 '23 15:02

Benoit