Другое

Исправление сбоя 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:

kotlin
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:

kotlin
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:

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):

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.

Содержание

Понимание основной причины

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, но это может вызвать проблемы с таймингом при запуске приложения.

kotlin
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 может быть проблематичной в более новых версиях. Попробуйте этот альтернативный подход:

kotlin
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

Временные решения

  1. Временное понижение версий проблемных пакетов до совместимых версий:
bash
yarn add react-native-gesture-handler@2.14.0
yarn add react-native-svg@14.1.0
  1. Исключение пакетов при обновлении и добавление их по одному:
json
{
  "dependencies": {
    "react-native-gesture-handler": "^2.14.0",
    "react-native-svg": "^14.1.0",
    // ... оставить другие пакеты на текущих версиях
  }
}
  1. Использование исключений пакетов в вашей конфигурации Gradle:
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. Рассмотрите возможность обновления этих значений:

gradle
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:

gradle
dependencies {
    classpath("com.facebook.react:react-native-gradle-plugin")  // Должно соответствовать вашей версии React Native
}

3. Проверка AndroidManifest.xml

Убедитесь, что ваш AndroidManifest.xml содержит правильное объявление класса приложения:

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 рассмотрите возможность пошагового обновления:

bash
# Сначала обновите до 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 и миграции ваших компонентов:

  1. Создайте новый проект с тем же именем пакета
  2. Скопируйте ваши экраны, компоненты и ресурсы
  3. Добавьте конкретные детали из вашего существующего проекта
  4. Перенавигируйте и повторно свяжите другие нативные модули

3. Временный возврат к Java

Некоторые пользователи обнаружили, что временное возвращение MainApplication.kt с .kt на .java решило проблему, как упоминается в ответе на StackOverflow:

java
// 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. Стратегия тестирования

После исправления немедленных проблем с сбоями:

  1. Сначала протестируйте основную функциональность
  2. Протестируйте каждый сторонний пакет индивидуально
  3. Протестируйте на нескольких устройствах/эмуляторах Android с разными уровнями API
  4. Протестируйте при разных условиях сети
  5. Используйте инструменты отчетности о сбоях, такие как Sentry, для обнаружения дополнительных проблем

3. Долгосрочное обслуживание

Чтобы предотвратить подобные проблемы в будущем:

  • Подпишитесь на заметки о выпусках React Native и объявления о критических изменениях
  • Регулярно обновляйте сторонние пакеты
  • Реализуйте автоматическое тестирование в CI/CD конвейерах
  • Внимательно отслеживайте отчеты о сбоях и отзывы пользователей

Источники

  1. Android app crash when upgrade from react-native 0.73.1 to 0.82.0 - Stack Overflow
  2. React Native 0.80.0 Android crash on app startup - GitHub Issue
  3. MainApplication.kt unresolved reference issues - React Native Community
  4. Getting “Unable to instantiate application” for MainApplication.kt - Stack Overflow
  5. React Native upgrade helper - React Native Community
  6. 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. Ключ заключается в систематическом решении проблем с таймингом инициализации и совместимостью пакетов, а не попытке исправить все сразу.

Авторы
Проверено модерацией
Модерация