Исправление сбоя React Native Android после обновления с 0.73.1 до 0.82.0
Решение проблемы NullPointerException в MainApplication.kt при обновлении React Native с версии 0.73.1 до 0.82.0. Полное руководство с исправлениями кода, решениями совместимости пакетов и обновлениями конфигурации сборки.
Приложение React Native вылетает на Android после обновления с версии 0.73.1 до 0.82.0
Я обновил свое приложение React Native с версии 0.73.1 до 0.82.0. Приложение работает идеально на iOS, но когда я пытаюсь собрать его для Android, оно успешно устанавливается, но сразу вылетает при открытии. Ошибка, похоже, связана с файлом MainApplication.kt.
Я следовал инструкциям React Native Upgrade Helper в процессе обновления и также переключился с Java на Kotlin.
Ошибка в Logcat при открытии приложения:
Process: com.myApp.dev, PID: 10748
java.lang.RuntimeException: Unable to create application com.myApp.MainApplication
...
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.Application com.facebook.react.ReactNativeHost.getApplication()' on a null object reference
MainApplication.kt:
package com.myApp
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList =
PackageList(this).packages.apply {},
)
}
override fun onCreate() {
super.onCreate()
loadReactNative(this)
}
}
MainActivity.kt:
package com.myApp
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
class MainActivity : ReactActivity() {
override fun getMainComponentName(): String = "MyApp"
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}
/android/build.gradle:
buildscript {
ext {
buildToolsVersion = "36.0.0"
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36
ndkVersion = "29.0.14206865"
kotlinVersion = "2.1.20"
googlePlayServicesAuthVersion = "19.2.0"
}
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("com.google.gms:google-services:4.4.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
allprojects {
repositories {
google()
}
}
}
apply plugin: "com.facebook.react.rootproject"
Зависимости (package.json):
"dependencies": {
"@babel/plugin-proposal-decorators": "^7.8.3",
"@brown-bear/react-native-autoheight-webview": "^2.0.4",
"@d11/react-native-fast-image": "^8.12.0",
"@dr.pogodin/react-native-fs": "^2.36.1",
"@invertase/react-native-apple-authentication": "^1.1.0",
"@mobeuv/react-native-user-agent": "^2.0.0",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-native-firebase/analytics": "^23.4.1",
"@react-native-firebase/app": "^23.4.1",
"@react-native-google-signin/google-signin": "^16.0.0",
"@react-native/metro-config": "^0.75.0-main",
"@react-native/new-app-screen": "^0.82.0",
"@react-navigation/bottom-tabs": "^7.4.9",
"@react-navigation/native": "^7.1.18",
"@react-navigation/native-stack": "^7.3.28",
"i18n-js": "^3.5.1",
"jwt-decode": "^2.2.0",
"lodash": "^4.17.15",
"md5": "^2.2.1",
"mobx": "^5.15.4",
"mobx-react-lite": "^1.5.2",
"moment": "^2.24.0",
"native-base": "^3.4.28",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
"query-string": "^6.12.1",
"react": "^19.1.1",
"react-dom": "^19.2.0",
"react-native": "0.82.0",
"react-native-dialog": "^5.6.0",
"react-native-draggable-flatlist": "^4.0.3",
"react-native-dropdown-picker": "^5.2.3",
"react-native-fbsdk-next": "^13.4.1",
"react-native-fix-image": "^2.1.0",
"react-native-gesture-handler": "^2.29.1",
"react-native-get-random-values": "^2.0.0",
"react-native-image-viewing": "^0.1.8",
"react-native-indicators": "^0.17.0",
"react-native-keyboard-aware-scrollview": "^2.1.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-modal": "^13.0.2",
"react-native-modal-dropdown": "^1.0.2",
"react-native-notifications": "^5.1.0",
"react-native-onesignal": "^5.2.13",
"react-native-orientation-locker": "^1.1.8",
"react-native-pages": "^0.9.0",
"react-native-reanimated": "^4.1.5",
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "^4.17.1",
"react-native-select-dropdown": "^1.4.0",
"react-native-side-menu": "https://github.com/vincentum/react-native-side-menu.git",
"react-native-snap-carousel": "^3.9.1",
"react-native-splash-screen": "^3.3.0",
"react-native-svg": "^15.14.0",
"react-native-swiper": "^1.6.0-nightly.5",
"react-native-vector-icons": "^10.3.0",
"react-native-version-number": "^0.3.6",
"react-native-video": "^6.17.0",
"react-native-webview": "^13.16.0",
"react-native-worklets": "^0.6.1",
"uuid": "^7.0.2",
},
Как можно исправить NullPointerException в MainApplication.kt при обновлении React Native с версии 0.73.1 до 0.82.0? Приложение работает нормально на iOS, но сразу после запуска вылетает на Android.
React Native приложения часто аварийно завершают работу на Android после крупных обновлений версий из-за изменений в нативной архитектуре Android, особенно при миграции с 0.73.1 на 0.82.0. NullPointerException в MainApplication.kt обычно возникает из-за проблем с порядком инициализации, загрузки списка пакетов или несовместимости сторонних пакетов в процессе миграции на Kotlin.
Содержание
- Понимание основной причины
- Распространенные решения для сбоя MainApplication.kt
- Проблемы совместимости пакетов
- Исправления конфигурации сборки
- Альтернативные подходы к миграции
- Стратегии предотвращения и тестирования
Понимание основной причины
NullPointerException, с которым вы сталкиваетесь, вызван несколькими взаимосвязанными проблемами, которые были введены в версиях React Native между 0.73.1 и 0.82.0. Как показывают результаты исследования, это хорошо задокументированная проблема, затрагивающая многих разработчиков в процессе этого обновления.
Ошибка java.lang.RuntimeException: Unable to create application com.myApp.MainApplication с конкретной причиной Attempt to invoke virtual method 'android.app.Application com.facebook.react.ReactNativeHost.getApplication()' on a null object reference указывает на то, что экземпляр ReactNativeHost не был правильно инициализирован до его доступа.
Как упоминается в обсуждении на StackOverflow, эта проблема особенно распространена при переключении с Java на Kotlin для класса MainApplication, поскольку порядок инициализации и ленивые свойства работают по-разному между этими двумя языками.
Распространенные решения для сбоя MainApplication.kt
1. Исправление порядка инициализации ReactHost
Наиболее немедленным решением является обеспечение правильного порядка инициализации в вашем MainApplication.kt. Текущая реализация использует ленивую инициализацию для reactHost, но это может вызвать проблемы с таймингом при запуске приложения.
package com.myApp
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
class MainApplication : Application(), ReactApplication {
private val _reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
)
}
override val reactHost: ReactHost
get() = _reactHost
override fun onCreate() {
super.onCreate()
loadReactNative(this)
}
}
Ключевые изменения:
- Разделение ленивой инициализации на приватное свойство
- Добавление правильного геттера для переопределенного свойства
- Удаление ненужного
.apply {}, которое может вызывать проблемы с инициализацией
2. Обновление инициализации PackageList
Исследования показывают, что инициализация PackageList может быть проблематичной в более новых версиях. Попробуйте этот альтернативный подход:
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
)
}
Убедитесь, что вы удалили блок .apply {}, так как он может мешать правильной инициализации.
3. Проверка отсутствующих импортов
Убедитесь, что у вас есть все необходимые импорты в MainApplication.kt. Исследования показывают, что некоторые пользователи сталкивались с ошибками “Unresolved reference: ReactHost”, что указывает на отсутствующие импорты.
Проблемы совместимости пакетов
Исследования показывают, что несколько сторонних пакетов известны тем, что вызывают сбои при обновлении React Native:
Проблемные пакеты
Согласно обсуждению на GitHub issue, эти пакеты часто вызывают сбои:
- react-native-gesture-handler (версия 2.29.1 в ваших зависимостях)
- react-native-svg (версия 15.14.0 в ваших зависимостях)
- @react-native-camera-roll/camera-roll
Временные решения
- Временное понижение версий проблемных пакетов до совместимых версий:
yarn add react-native-gesture-handler@2.14.0 yarn add react-native-svg@14.1.0
- Исключение пакетов при обновлении и добавление их по одному:
{
"dependencies": {
"react-native-gesture-handler": "^2.14.0",
"react-native-svg": "^14.1.0",
// ... оставить другие пакеты на текущих версиях
}
}
- Использование исключений пакетов в вашей конфигурации Gradle:
project.ext.excludeReactNativeGroup = "com.facebook.react"
implementation(project(":react-native-gesture-handler")) {
exclude group: "com.facebook.react"
}
Исправления конфигурации сборки
1. Обновление конфигурации Gradle
Ваша текущая конфигурация сборки может потребовать настроек для React Native 0.82.0. Рассмотрите возможность обновления этих значений:
buildscript {
ext {
buildToolsVersion = "34.0.0" // Обновлено с 36.0.0
minSdkVersion = 21 // Рассмотрите возможность понижения с 24
compileSdkVersion = 34 // Обновлено с 36
targetSdkVersion = 34 // Обновлено с 36
ndkVersion = "25.1.8937393" // Обновленная версия
kotlinVersion = "1.9.20" // Обновлено с 2.1.20
googlePlayServicesAuthVersion = "21.2.0" // Обновлено
}
}
2. Исправление React Native Gradle Plugin
Убедитесь, что вы используете правильную версию React Native Gradle plugin:
dependencies {
classpath("com.facebook.react:react-native-gradle-plugin") // Должно соответствовать вашей версии React Native
}
3. Проверка AndroidManifest.xml
Убедитесь, что ваш AndroidManifest.xml содержит правильное объявление класса приложения:
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
Альтернативные подходы к миграции
1. Пошаговые обновления
Вместо прямого перехода с 0.73.1 на 0.82.0 рассмотрите возможность пошагового обновления:
# Сначала обновите до 0.74.0
npx react-native upgrade 0.74.0
# Протестируйте и исправьте проблемы
# Затем обновите до 0.75.0
npx react-native upgrade 0.75.0
# Продолжайте до достижения 0.82.0
2. Миграция через новый проект
Как предлагается в обсуждении на Reddit, рассмотрите возможность создания нового проекта с React Native 0.82.0 и миграции ваших компонентов:
- Создайте новый проект с тем же именем пакета
- Скопируйте ваши экраны, компоненты и ресурсы
- Добавьте конкретные детали из вашего существующего проекта
- Перенавигируйте и повторно свяжите другие нативные модули
3. Временный возврат к Java
Некоторые пользователи обнаружили, что временное возвращение MainApplication.kt с .kt на .java решило проблему, как упоминается в ответе на StackOverflow:
// MainApplication.java (временное исправление)
package com.myApp;
import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactHost;
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative;
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost;
public class MainApplication extends Application implements ReactApplication {
@Override
public ReactHost getReactHost() {
return getDefaultReactHost(
getApplicationContext(),
new PackageList(this).packages,
);
}
@Override
public void onCreate() {
super.onCreate();
loadReactNative(this);
}
}
Стратегии предотвращения и тестирования
1. Список проверок перед обновлением
Перед обновлением React Native убедитесь:
- Все зависимости обновлены до вашей текущей версии
- Ваше приложение собирается и успешно запускается на обеих платформах
- У вас есть резервная копия текущей кодовой базы
- Вы проверили React Native Upgrade Helper
2. Стратегия тестирования
После исправления немедленных проблем с сбоями:
- Сначала протестируйте основную функциональность
- Протестируйте каждый сторонний пакет индивидуально
- Протестируйте на нескольких устройствах/эмуляторах Android с разными уровнями API
- Протестируйте при разных условиях сети
- Используйте инструменты отчетности о сбоях, такие как Sentry, для обнаружения дополнительных проблем
3. Долгосрочное обслуживание
Чтобы предотвратить подобные проблемы в будущем:
- Подпишитесь на заметки о выпусках React Native и объявления о критических изменениях
- Регулярно обновляйте сторонние пакеты
- Реализуйте автоматическое тестирование в CI/CD конвейерах
- Внимательно отслеживайте отчеты о сбоях и отзывы пользователей
Источники
- Android app crash when upgrade from react-native 0.73.1 to 0.82.0 - Stack Overflow
- React Native 0.80.0 Android crash on app startup - GitHub Issue
- MainApplication.kt unresolved reference issues - React Native Community
- Getting “Unable to instantiate application” for MainApplication.kt - Stack Overflow
- React Native upgrade helper - React Native Community
- React Native 0.78 Android build issues - GitHub Issue
Заключение
NullPointerException в MainApplication.kt при обновлении React Native с 0.73.1 на 0.82.0 - это распространенная, но решаемая проблема. Начните с исправления порядка инициализации ReactHost и удаления проблемного блока .apply {} из инициализации PackageList. Если это не решит проблему, временно понизьте несовместимые пакеты, такие как react-native-gesture-handler и react-native-svg, до известных работающих версий.
Для более постоянного решения рассмотрите пошаговые обновления или создание нового проекта и миграцию ваших компонентов. Всегда поддерживайте регулярные резервные копии и всестороннее тестирование в процессе любого обновления React Native. Ключ заключается в систематическом решении проблем с таймингом инициализации и совместимостью пакетов, а не попытке исправить все сразу.