Java.lang.NoClassDefFoundError en versiones anteriores de Android SDK

Liberé una versión de mi aplicación en Google Play y me desperté esta mañana con una serie de clientes infelices. La última versión de la aplicación integra la compatibilidad con un monitor de frecuencia cardíaca Bluetooth Low Energy (BTLE).

La aplicación funciona bien en Android 4.3 y 4.4, pero se bloquea en 4.0, 4.1 y 4.2 con el siguiente error.

FATAL EXCEPTION: main java.lang.NoClassDefFoundError: com.eiref.boatcoach.MainActivity at com.eiref.boatcoach.WhatToDo.onClick(WhatToDo.java:274) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:152) at android.app.ActivityThread.main(ActivityThread.java:5132) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) 

El error se produce al crear un Intent en un Onclick simple similar al siguiente …

 public void onClick(View v) { Intent i = new Intent(this, MainActivity.class); startActivity(i); } 

Después de salir corriendo y comprar una tableta 4.2 para poder replicar el problema, he llegado a la conclusión de que tiene que ver con esta nueva versión de la aplicación compatible con Bluetooth LE, que está habilitado en SDK 4.3 y posteriores. Si elimino todas las referencias a Bluetooth en MainActivity, el fallo desaparece en los dispositivos 4.2 y anteriores.

Mi comprensión de la lectura de la documentación fue que se podría escribir una aplicación que incluye la funcionalidad de Bluetooth LE y que se ejecuta en los dispositivos más antiguos, siempre y cuando se tuvo cuidado de no ejecutar código BTLE utilizando algo como el siguiente …

 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) return; BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); mBluetoothAdapter = manager.getAdapter(); //etc. 

Por lo tanto, mi manifest.xml no incluye lo siguiente, ya que impediría la descarga a dispositivos más antiguos y, obviamente, quiero mantener una base de código único, si es posible …

 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> 

Primera pregunta, ¿es mi hipótesis anterior ser capaz de incluir el código BTLE en SDKs anteriores a 4.3 correctos? Si no, ¿realmente necesito crear dos versiones de la aplicación … una para la gente que usa 4.3 y más tarde y otra para todos los demás?

Hay muchos posts de StackOverflow sobre java.lang.NoClassDefFoundError y creo que he leído la mayoría de los relevantes. Muchos sugieren que examine la ruta de compilación de Java para asegurarse de que las bibliotecas privadas de Android y las dependencias de Android estén marcadas. Son. Algunos sugieren mover la carpeta gen antes de la carpeta src, pero esto no parece hacer una diferencia.

Me gustaría publicar una imagen de la Eclipse Java Build Path, pero como este es mi primer post no tengo los 10 puntos de reputación necesarios para insertar una imagen, por lo que aquí es otro post que he seguido … Android java.lang.NoClassDefFoundError

Así que, segunda pregunta, cualquier otra reflexión sobre lo que podría estar mal con el camino de construcción?

Muchas gracias de antemano.


Actualizar … de alguna manera por hacer una pregunta tengo suficientes puntos para publicar imágenes de la java construir ruta. Como @Ashoke señala que creo que tiene algo que ver con el camino de construcción equivocado o bibliotecas de soporte.

Eclipse Orden y Exportación

Bibliotecas Eclipse

Trate de obtener todo el código relacionado Ble en una clase separada que sólo instancia en absoluto si en un dispositivo con los niveles de API necesarios. Creo que sin esto las call-backs podría estar llevando a sus problemas.

He encontrado que la definición de la devolución de llamada estáticamente en la actividad obtiene un error, pero encerrándolo en una función con una comprobación de api no producirá el mismo error.

en lugar de:

  @TargetApi(Build.VERSION_CODES.LOLLIPOP){ public class RouteMapActivity extends ActionBarActivity private BluetoothAdapter.LeScanCallback mScanCallback = new ScanCallback() {...} 

Solía:

 private void setUpLeCallbacks(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); for (BTDeviceName device : mTestPointsToRead) { ScanFilter filter = new ScanFilter.Builder().setDeviceAddress(device.le_serial).build(); filters.add(filter); } mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } }; }else { mLeScanCallback= new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { } }; } } 

Ahora que está utilizando API que podrían no estar disponibles en versiones anteriores de Android, asegúrese de que está empaquetando la aplicación con la biblioteca de soporte adecuada.

Por ejemplo, vea esta muestra de android BluetoothLeGattSample . Utiliza la lib de soporte siguiente.

  dependencies { // Add the support lib that is appropriate for SDK 18 compile "com.android.support:support-v13:19.0.+" } 

Vea los documentos de android para las instrucciones de eclipse para la configuración de la biblioteca de soporte

Esto es normal para obtener esta excepción en <4.3 dispositivos porque BLE no existía, por lo que su código compilado no puede encontrar las clases correspondientes en el sistema operativo. No hay nada malo en tu camino de construcción.

La mejor solución es proteger su código BLE en una cláusula if , probando la capacidad BLE en tiempo de ejecución. También debe filtrar la versión del sistema operativo en el if like:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {...} 

Debe declarar android:required="false" para esta característica, significa que la aplicación prefiere utilizar la función si está presente en el dispositivo, pero que está diseñada para funcionar sin la característica especificada, si es necesario.

 <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" /> 
  • Java.lang.NoClassDefFoundError en la versión de Android inferior a Lollipop
  • NoClassDefFoundError en Android
  • Android - Google Maps API v2 - NoClassDefFoundError
  • Obtener TypeNotPresentException seguido de ClassNotFoundException o NoClassDefFoundError en todas las versiones de android excepto android L
  • Crash: java.lang.NoClassDefFoundError: android.support.v7.appcompat.R $ layout
  • HtmlUnit en Android: Dependencias
  • NoClassDefFoundError Android Project
  • NoClassDefFoundError debajo de SDK 21
  • Extraño error NoClassDefFoundError al iniciar una versión firmada APK con proguard habilitado
  • NoClassDefFoundError al usar greenDao
  • Estudio de Android: java.lang.NoClassDefFoundError
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.