Android Gradle: Install all build types on one device

旧时模样 提交于 2019-12-04 12:07:20
Benoit

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!