Реагирование

Мы создали приложение, использующее React Native для улучшения UX и функций нашего предыдущего приложения Cordova.

Все прошло хорошо. Несколько месяцев разработки, QA, обзор приложений, а затем мы опубликовали в App Store. Он работал на всех устройствах, которые мы пробовали, с iPhone 4s на iPhone 6s +, мы протестировали на iOS 8.3 (самый ранний симулятор, который вы можете скачать через xCode) до 10.0.

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

Мы исследовали "сбои" в xCode, и они, очевидно, не отображались, потому что сотни пользователей столкнулись с крахом, и нам удалось увидеть только несколько - которые, казалось, не были связаны с запуском.

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

Любые идеи, где я должен смотреть дальше? Мы действительно не хотим возвращаться к старой версии и терять месяцы работы.

Приложение использует около ~ 100 МБ памяти, когда все загружается, поэтому я не должен быть проблемой. Это происходит во всех версиях iOS на всех устройствах. Мы не можем изолировать ошибку только от конкретных пользователей.

Ответ 1

Проблема решена из-за плохой связи между нами и нашими пользователями. Приложение фактически НЕ сбой, просто не запускается (что является одним и тем же в глазах некоторых пользователей).

После того, как мы обнаружили это, мы поняли, что одно из событий не срабатывает (тот, который скрывает расширенный экран заставки), и именно здесь пользователи застревают. Одна из библиотек, которые мы использовали, неправильно обработала сценарий ошибок, и это сделало нашу работу намного сложнее. Мне посчастливилось попасть в это состояние во время тестирования, и я смог продолжить оттуда.

Я обновил код для обработки этого сценария, и проблема теперь решена.

Ответ 2

Когда нет какого-либо другого способа анализа, я прибегаю к скромному отказу от регистрации.

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

  • Самое первое, что должно сделать приложение, это проверить, был ли успешный запуск PREVIOUS успешным или нет, прочитав некоторые значения, которые должны были быть записаны по умолчанию в начале и в конце предыдущего запуска (подробности на следующем шаге). Если предыдущий запуск НЕ был успешным, дайте пользователю возможность запускаться в каком-то "безопасном режиме" (это означает, что это зависит от того, что приложение пытается делать при запуске, но для меня это означало не загрузку каких-либо данных или выполнение ничего особенного, кроме отображения пользовательского интерфейса, лишенного каких-либо зависимых от данных элементов, для некоторых приложений он даже может зайти так далеко, чтобы загрузить совершенно другой пользовательский интерфейс, который включает только инструменты диагностики или средства удаления данных / reset).
  • Следующее, что должно сделать приложение после определения того, что предыдущий запуск был ОК (или это первый запуск), заключается в том, чтобы как можно скорее написать какой-то статус "startupBegan" по умолчанию, а затем некоторые своего рода статус "startupCompleted", только когда он полностью завершил запуск (что означает "полностью завершенный запуск", зависит от приложения, но вы действительно хотите быть уверенным, что пользовательский интерфейс полностью реагирует на данный момент и отображает все, что ему нужно, это может быть немного сложно определить иногда, поскольку некоторые вещи не запускаются до тех пор, пока экран заставки не исчезнет и т.д., если вы не можете найти какой-либо другой способ, я полагаю, вы можете запустить это с помощью таймера, но это будет довольно уродливый - лучше найти какой-то способ определить, когда запуск действительно полностью завершен). Эти значения могут использоваться, чтобы определить, начался ли запуск, но не завершился, и какой шаг 1 (выше) используется, чтобы определить, был ли предыдущий запуск успешным или нет.
  • Включить большое количество протоколирования в приложении и записать журналы в файл. Я думаю, что есть сторонние инструменты, которые вы можете сделать, но я написал свой собственный метод (ниже), который просто перенаправляет stderr в файл, если он работает в процессе производства и не связан с XCode. Обратите внимание, что NSLog() записывает в stderr, а не в stdout.
  • Дайте приложению возможность отправлять файлы журналов электронной почты на ваш адрес электронной почты поддержки - это должно быть доступно в безопасном режиме приложения (а также в обычном режиме). В обычном режиме я делаю это довольно неясным, чтобы пользователь не замечал, когда все в порядке (например, кнопка в нижней части окна "Настройки" или "О себе" ). Я говорю пользователю, как найти кнопку, когда они отправили запрос поддержки, для которого мне действительно нужны журналы.
  • Поворот журналов при каждом запуске, чтобы они не потребляли слишком много места, но обязательно сохраните несколько оборотов, иначе вы получите журнал из режима безопасного режима, который бесполезен.

Возможны многие варианты. Включая такие вещи, как только включить ведение журнала, если пользователь настроил для него настройки. Возможно, вам придется добавить много ошибок в некоторых областях кода, когда пользователь сообщает о какой-либо конкретной проблеме, а затем удаляет его снова после устранения проблемы (если вас беспокоит проблема с производительностью/хранилищем, связанная с протоколированием).

Для моего приложения (Objective-C) места для включения моего кода для записи статуса запуска по умолчанию были такими, как показано ниже (могут быть лучшие места, более подходящие для вашего приложения):

  • "startupBegan" на ранней стадии делегирования приложения application:didFinishLaunchingWithOptions:
  • "startupCompleted" в конце диспетчера просмотра viewDidAppear (NOT viewWillAppear! там много чего может пойти не так, как между этими двумя отправленными)

PS. Моим старым методом перенаправления и вращения журнала было что-то вроде этого (Objective-C):

- (void)logRedirectRotate {
    // If stderr not going to an XCode console (then running in production)
    if ( ! isatty(STDERR_FILENO) ) {
        // Rotate logs

        int rotationsCount = 3;
        NSMutableArray *logRotations = [NSMutableArray array];

        for ( int i = 0; i < rotationsCount; i++ ) {
            [logRotations addObject:[pathToLogsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"appnameorbundleid.%d.log", i]]];
        }

        [[NSFileManager defaultManager] removeItemAtPath:[logRotations lastObject] error:nil];

        for ( int i = rotationsCount - 1; i > 0; i-- ) {
            [[NSFileManager defaultManager] moveItemAtPath:[logRotations objectAtIndex:i - 1] toPath:[logRotations objectAtIndex:i] error:nil];
        }

        //  Redirect stderr to current log file rotation
        freopen([[logRotations objectAtIndex:0] cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
    }
}

Ответ 3

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

Дело здесь в том, что приложение только врезается в производство, поэтому это что-то, что срабатывало только на производстве, которое испортило сборку. В нашем случае виновник был одним из React dependencies, который выполняет минимизацию.

Вещи убрать:

  • Следите за обновлениями ваших зависимостей
  • Использовать журнал сбоев