ClassNotFoundException con sabores de productos y Kotlin

Tengo un proyecto escrito principalmente en Kotlin, pero con algunas classs de Java. El proyecto está muy avanzado ahora, y quería agregar la posibilidad de cambiar entre diferentes entornos, para los cuales utilicé sabores:

productFlavors { prod { dimension "default" buildConfigField 'boolean', 'FABRIC', 'true' applicationId = "com.myapp" } beta { dimension "default" buildConfigField 'boolean', 'FABRIC', 'true' applicationId = "com.myapp.beta" } dev { dimension "default" buildConfigField 'boolean', 'FABRIC', 'false' applicationId = "com.myapp.dev" } } 

Sin embargo, cuando corro en un sabor que no es producción (que no cambia applicationId) obtengo una ClassDefNotFoundException para una class java:

 Caused by: java.lang.ClassNotFoundException: Didn't find class "com.myapp.beta.ui.view.ScrollBehavior" on path: DexPathList[[zip file "/data/app/com.myapp.beta-1/base.apk"],nativeLibraryDirectories=[/data/app/com.myapp.beta-1/lib/arm64, /system/lib64, /vendor/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:380) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) ... 33 more 

Estoy usando Android Studio 3.0 beta 4 con Kotlin plugin versión 1.1.3-2.

Crear file:

 apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' // Use experimental kapt implementation repositories { mavenCentral() maven { url "http://dl.bintray.com/ttymsd/maven" } maven { url 'https://jitpack.io' } } android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "com.myapp" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } sourceSets { main.java.srcDirs += 'src/main/java' } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } flavorDimensions "default" productFlavors { prod { dimension "default" buildConfigField 'boolean', 'FABRIC', 'true' applicationId = "com.myapp" } beta { dimension "default" buildConfigField 'boolean', 'FABRIC', 'true' applicationId = "com.myapp.beta" } dev { dimension "default" buildConfigField 'boolean', 'FABRIC', 'false' applicationId = "com.myapp.dev" } } dataBinding { enabled = true } dependencies { (...) } } 

Manifiesto:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.myapp"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:name=".MyApp" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/MyTheme"> <activity android:name=".ui.dashboard.DashboardListActivity" android:launchMode="singleTop" android:configChanges="orientation|keyboardHidden|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> 

Parte relevante en el código:

 <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:theme="@style/MycujooPlayerTheme.AppBarOverlay" app:layout_behavior=".ui.view.ScrollBehavior"> 

Estás definiendo tu comportamiento como

 app:layout_behavior=".ui.view.ScrollBehavior" 

que es una definición relativa. En este caso, relativo al package de la aplicación.

Entonces, el nombre realmente usado es context.getPackageName() + name y, por lo tanto, el ID de la aplicación que definió se usa como prefijo.

Para cargar el comportamiento correcto, debe definirlo como un nombre completamente calificado

 app:layout_behavior="com.myapp.ui.view.ScrollBehavior" 

También podría usar resources de cadena aquí.

Este no es un problema de Kotlin.

Causado por: java.lang.ClassNotFoundException: no encontró la class "com.myapp. Beta .ui.view.ScrollBehavior"

Del doc de android

Cada aplicación de Android tiene una ID de aplicación única que se parece a un nombre de package de Java, como com.example.myapp. Este ID identifica de forma única su aplicación en el dispositivo y en Google Play Store

 <manifest package="com.myapp" > 

o a veces incluso he visto (nunca uso esto) :

 <manifest package="${applicationId}" > 

Cambiarlo significa que está cambiando la reference de su package de aplicación. las classs ubicadas en com.myapp se com.myapp.beta en com.myapp.beta . Y luego tus classs no serán encontradas.

Una forma de trabajar con, es definir el sabor como (pospuse los otros valores por simplicidad) :

 prod { applicationId = "com.myapp" } beta { applicationId = "com.myapp.beta" } dev { applicationId = "com.myapp.dev" } 

o solo

 beta { applicationIdSuffix ".beta" } dev { applicationIdSuffix ".dev" } 

Editar después de pusblish build.gradle

Preste atención para agregar un sufijo o un ID de aplicación completo:

 //This will be append to your application id //applicationIdSuffix = "com.myapp.beta", should be applicationIdSuffix = ".beta" 

o

 //This will replace your application Id applicationId "com.myapp.beta" 
  • ¿Cómo hacer inferencia tipo Kotlin desde la reflexión KClass?
  • ¿Cómo establecer el atributo de peso de forma dinámica desde el código de Kotlin?
  • ¿Cómo se convierte la encoding win1251 a UTF8 dentro de Kotlin?
  • Kotlin y Dagger: ¿Puedo usar @Inject para un object que todavía lo hace nulo / opcional?
  • Cómo configurarOnEditorActionListener con Kotlin
  • Extensiones y variables de Kotlin para Android
  • ¿Usar EventBus para finalizar una actividad de la actividad base?
  • ¿Cómo puedo ejecutar una sola testing de Android usando Kotlin?
  • objects sellados de la class que misteriosamente se vuelven nulos cuando se hace reference a otro object compañero
  • GoogleApiClient: No se puede conectar y ejecutar manualmente el inicio de session después
  • Kotlin Pass en un tipo que implementa una interfaz parametrizada