Как получить отчеты о сбоях из загружаемого приложения?

Поскольку Crashlytics не работает с загружаемыми приложениями из коробки, я ищу оптимальный способ перехватить и сообщить о любом потенциальном исключении, создаваемом во время выполнения. Интересно, почему они не сообщаются автоматически в консоли разработчика Google Play?

Google уже объявила, что будущее обновление Android Wear будет иметь встроенную поддержку Wi-Fi, но даже тогда не все устройства будут оснащены соответствующим оборудованием.

В этом случае моя первоначальная идея заключалась в создании подкласса Application и реализации Thread.UncaughtExceptionHandler . Затем каждое исключение должно быть упорядочено и отправлено на телефонную трубку, используя MessageApi . Расширение WearableListenerService на телефоне получит сообщение, отменит исключение и передаст его, например, Crashlytics.

Однако это вызывает еще несколько вопросов. Существует риск того, что соединение Bluetooth между носимым и телефонной трубкой будет нарушено, поэтому все ошибки должны быть поставлены в очередь и сохранены в файловой системе носимого устройства.

Это кажется излишним для простого отчета о сбоях. Есть ли более простой способ сделать это?

Solutions Collecting From Web of "Как получить отчеты о сбоях из загружаемого приложения?"

Не используйте MessageApi для этой цели, кроме DataApi . Тогда вам не нужно беспокоиться о потерянном подключении Bluetooth.

Как это работает:

  1. Когда происходит сбой, установите DataItem с крахом на носимом;

  2. В конечном итоге он будет доставлен на мобильное устройство.

  3. Отправьте информацию о DataItem с мобильного устройства и удалите DataItem .

Дополнительная информация здесь: http://developer.android.com/training/wearables/data-layer/index.html

Вот проект моего решения. Как предложил @gruszczy , я использую DataApi .

Носимое применение:

 public class WApplication extends Application implements Thread.UncaughtExceptionHandler { private static final String LOG_TAG = WApplication.class.getSimpleName(); private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler; ... @Override public void onCreate() { super.onCreate(); mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(Thread thread, final Throwable throwable) { Log.e(LOG_TAG, "Uncaught exception thrown."); WearableService.launchService(throwable, WApplication.this); mDefaultUncaughtExceptionHandler.uncaughtException(thread, throwable); } } 

Носимый сервис:

 public class WearableService extends Service { ... public static void launchService(Throwable throwable, Context context) { Intent startServiceIntent = new Intent(context, WearableService.class); startService.putExtra(EXTRA_KEY_EXCEPTION, throwable); context.startService(startServiceIntent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Throwable throwable = (Throwable) intent.getSerializableExtra(KEY_EXCEPTION); sendExceptionToMobile(throwable); return super.onStartCommand(intent, Service.START_REDELIVER_INTENT, startId); } private void sendExceptionToMobile(final Throwable throwable) { if (throwable == null) { return; } Log.d(LOG_TAG, "Sending exception to mobile..."); PutDataMapRequest putDataMapReq = PutDataMapRequest .create(WearCommunicationConstants.PATH_EXCEPTION); DataMap dataMap = putDataMapReq.getDataMap(); StringWriter sw = new StringWriter(); throwable.printStackTrace(new PrintWriter(sw)); String stackTrace = sw.toString(); dataMap.putString(WearCommunicationConstants.KEY_STACK_TRACE, stackTrace); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq); pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>() { @Override public void onResult(final DataApi.DataItemResult result) { if (result.getStatus().isSuccess()) { Log.d(LOG_TAG, "DataItem synced: " + result.getDataItem().getUri()); } else { Log.e(LOG_TAG, "Failed to sync DataItem: " + result.getStatus().getStatusCode() + ", " + result.getStatus().getStatusMessage()); } } }); } } 

Мобильный сервис:

 public class MobileService extends WearableListenerService { ... @Override public void onDataChanged(DataEventBuffer dataEvents) { Log.d(LOG_TAG, "Data changed, data event(s) received."); for (DataEvent event : dataEvents) { Log.d(LOG_TAG, "Data event type: " + event.getType()); switch (event.getType()) { case DataEvent.TYPE_CHANGED: DataItem item = event.getDataItem(); DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); switch (item.getUri().getPath()) { case WearCommunicationConstants.PATH_EXCEPTION: Log.e(LOG_TAG, "Received exception from a wearable device."); String stackTrace = dataMap .getString(WearCommunicationConstants.KEY_STACK_TRACE); Utils.logWithCrashlytics(stackTrace); break; // ... } break; case DataEvent.TYPE_DELETED: // ... } } } } 

Я решил эту проблему следующим образом:

Интегрируйте эту библиотеку в свой проект. Эта библиотека будет передавать все исключения из приложения для ношения в мобильное приложение.

Если вы не используете proguard – вы можете просто использовать исключения ExceptionWear и исключения журналов на стороне мобильного приложения в крахлитики.

в противном случае

Когда вы получаете бросок на стороне мобильного приложения, вы можете записать его в crashlytics, но есть проблема:
Если мы создадим приложение Mobile + wear с использованием функции плагина Android, у нас будет что-то вроде этого:

 dependencies { compile 'com.google.android.gms:play-services:5.0.+@aar' ...lots of cool libs... wearApp project(':wear') } 

И примените плагин crashlytics для обоих приложений (мобильный и изнашиваемый), тогда во время использования приложения для изнашивания здания вы можете увидеть, что после выполнения задачи и задачи deguard (задачи градиента) плагин crashlytics не хранит и не загружает Deobs, и в результате – stacktraces не переназначаются ( Retraced) на приборной панели crashlytics:

: Wear: crashlyticsCleanupResourcesRelease // ОЖИДАЕТСЯ: износ: crashlyticsUploadStoredDeobsRelease // ОЖИДАЕМОЕ: износ: crashlyticsGenerateResourcesRelease // ОЖИДАЕМЫЙ
: Wear: generateReleaseResValues ​​UP-TO-DATE
: одежда: generateReleaseResources
: одежда: mergeReleaseResources
: одежда: processReleaseResources
: одежда: generateReleaseSources
: Одежда: compileReleaseJava
: Одежда: proguardRelease
: Wear: dexRelease // NO crashlytics хранить и загружать задачи Deobs: wear: processReleaseJavaRes UP-to-DATE
: одежда: shrinkReleaseResources

Но когда создается приложение для одежды (износ ap похож на зависимость от мобильного приложения), то начинается сборка мобильных приложений, и во время процесса сборки мобильных приложений процесс crashlytics работает хорошо:

: Mobile: crashlyticsCleanupResourcesRelease // ОЖИДАЕМОЕ: mobile: crashlyticsUploadStoredDeobsRelease // ОЖИДАЕМОЕ: mobile: crashlyticsGenerateResourcesRelease // ОЖИДАЕМОЕ
: Mobile: generateReleaseResValues ​​UP-TO-DATE
: Мобильный телефон: generateReleaseResources
: Мобильный: mergeReleaseResourcesknown
: Мобильный телефон: processReleaseResources
: Мобильный телефон: generateReleaseSources
: Мобильный: compileReleaseJava
: Мобильный: proguardRelease
: Мобильный: dexRelease
: Mobile: crashlyticsStoreDeobsRelease // ОЖИДАЕМОЕ: mobile: crashlyticsUploadDeobsRelease // ОЖИДАЕМОЕ: mobile: crashlyticsCleanupResourcesAfterUploadRelease // ОЖИДАЕМОЕ
: Мобильный: lintVitalRelease
: Mobile: compileReleaseNdk UP-TO-DATE
: Mobile: processReleaseJavaRes UP-TO-DATE
: Мобильный телефон: shrinkReleaseResources

Таким образом, во время стандартного процесса сборки износ модулей deobs не загружается, но есть обходное решение:

Если вы начинаете строить приложение для одежды отдельно, а затем вручную загружать пакет apk в ресурсах мобильного модуля, а затем загружать деобы, загруженные успешно, и вы можете наблюдать восстановленные сбои на приборной панели.

Но мне лично не нравится ручной способ сборки apk, поэтому я попытался сделать следующее:
Сначала просто создайте только ношение приложения. Deobs будут загружены в crashlytics. Затем выполните полную сборку, используя функцию «wearApp project (': wear')» и, похоже, она работает.

Во всяком случае, я жду поддержки android-wear от crashlytics из коробки.

В процессе сборки можно загружать деобы мобильных устройств и носить их.

Концепция:
1. Обеспечить, чтобы мобильный и изнашиваемый материал имели уникальные сопоставления
2. Объединить сопоставления износа с мобильными сопоставлениями перед загрузкой

1. Настроить proquard (обычно proguard-rules.pro)
Для одежды добавьте:

 -useuniqueclassmembernames 

Для мобильного добавить:

 -useuniqueclassmembernames -applymapping ../wear/build/outputs/mapping/release/mapping.txt 

Это изменение гарантирует, что у вас есть уникальные имена по сравнению с мобильными и изнашиваются, применяя сопоставления сборки одежды с мобильным сборкой.

2. Настройте сборку для объединения map.txt
Добавить в build.gradle для мобильных устройств:

 // allows to use Crashlytics also for wear by merging the mappings of wear into the // mappings of mobile //noinspection GroovyAssignabilityCheck task mergeMappings(dependsOn: "transformClassesAndResourcesWithProguardForRelease") << { File wearMappingFile = new File("wear/build/outputs/mapping/release/mapping.txt"); File mobileMappingFile = new File("mobile/build/outputs/mapping/release/mapping.txt"); if (wearMappingFile.exists() && mobileMappingFile.exists()) { println("merge mapping.txt") java.nio.file.Files.copy(wearMappingFile.toPath(), new FileOutputStream(mobileMappingFile, true)) } // else we are on the wear build and the mobile build was not yet executed } afterEvaluate { project.("crashlyticsStoreDeobsRelease").dependsOn(mergeMappings); } 

Добавляет сопоставления износа к мобильным сопоставлениям перед crashlyticsStoreDeobsRelease.