(Flutter) HTTP-запрос не отвечает для новых устройств Android

Вопрос или проблема

Я использую Flutter для создания кроссплатформенного приложения, и эта ошибка произошла только на самых новыхAndroid-устройствах, таких как Galaxy S23 Ultra и Galaxy S24+.

Future<int> register(
    String name, 
    String password, 
    String phoneNo, 
    String birthday, 
    String gender
    ) async {
      var pref = await SharedPreferences.getInstance();
      var token = pref.getString(SharedPreferencesKeys.fcmToken) ?? '';
      Map data = {
        'username': name,
        'userbirth': birthday,
        'gender': gender,
        'phoneno': phoneNo,
        'password': password,
        'fcm': token,
      };
      var url = Uri.parse(Url.getSignupUrl());
      var body = json.encode(data);
      try {
        var response = await http.post(
          url,
          headers: {
            'Content-Type': 'application/json',
          },
          body: body,
        ).timeout(const Duration(seconds: 10));
        
        if (response.statusCode == 200) {
          Map<String, dynamic> decodedJson = json.decode(response.body); // для будущего использования
          String accessToken = decodedJson['result']['tokens']['accessToken']['accessToken'];
          int accessTokenTimeout = decodedJson['result']['tokens']['accessToken']['timeout'];
          String refreshToken = decodedJson['result']['tokens']['refreshToken']['refreshToken'];
          int refreshTokenTimeout = decodedJson['result']['tokens']['refreshToken']['timeout'];
          String userId = decodedJson['result']['userId'];
          const storage = FlutterSecureStorage(
              aOptions: AndroidOptions(
                encryptedSharedPreferences: true,
              )
            );
          print('register: $userId, $name, $phoneNo, $birthday, $sex');
          storage.write(key: SecureStorageKeys.userId, value: userId);
          storage.write(key: SecureStorageKeys.name, value: name);
          storage.write(key: SecureStorageKeys.phoneNo, value: phoneNo);
          storage.write(key: SecureStorageKeys.birthday, value: birthday);
          storage.write(key: SecureStorageKeys.sex, value: sex);
          await pref.setString(SharedPreferencesKeys.accessToken, accessToken); 
          await pref.setString(SharedPreferencesKeys.refreshToken, refreshToken);
          await pref.setInt(SharedPreferencesKeys.accessTokenTimeout, accessTokenTimeout);
          await pref.setInt(SharedPreferencesKeys.refreshTokenTimeout, refreshTokenTimeout);
          return(response.statusCode);
        } else {
          return(-1);
        }
      } catch (e) {
          return(-1);
      }
  }

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

Также конечная точка API – http://WW.XXX.YYY.ZZZ:3000/my/route

Я думал, что код работает, потому что он нормально работал на любых устройствах iOS и некоторых старых версиях Android (Galaxy Tab A7 Lite и эмуляторы Android из Android Studio – они используют Android 14)

Я также добавил файл конфигурации в main/res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">13.125.243.222</domain>
    </domain-config>
</network-security-config>

А это мой Android Manifest в разделе main

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="mylabel"
        android:name="${applicationName}"
        android:extractNativeLibs="true"
        android:networkSecurityConfig="@xml/network_security_config"
        android:usesCleartextTraffic="true"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize"
            android:showWhenLocked="true"
            android:turnScreenOn="true"
            >
            <!-- Указывает тему Android, которую следует применить к этому Activity, как только
                 процесс Android был запущен. Эта тема видима для пользователя
                 во время инициализации пользовательского интерфейса Flutter. После этого эта тема продолжает
                 определять фон окна за пользовательским интерфейсом Flutter. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity 
            android:name=".VerificationActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"
        />
        <!-- Не удаляйте метаданные ниже.
             Это используется инструментом Flutter для генерации GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />


            <receiver
                android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver"
                android:exported="false" />
            <receiver
                android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver"
                android:exported="false" >
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
                    <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                    <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
                </intent-filter>
            </receiver>
    </application>
    <!-- Необходимо для запроса активностей, которые могут обрабатывать текст, см.:
         https://developer.android.com/training/package-visibility и
         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

         В частности, это используется движком Flutter в io.flutter.plugin.text.ProcessTextPlugin. -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>
    <!-- Сообщите в Google Play Store, что ваше приложение использует Bluetooth LE
     Установите android:required="true", если Bluetooth необходим -->
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />

    <!-- Новые разрешения Bluetooth в Android 12
    https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- наследие для Android 9 и ниже -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
</manifest>

Flutter Doctor, если кто-то заинтересован

[✓] Flutter (Канал stable, 3.24.0, на macOS 14.2 23C64 darwin-arm64, локаль ko-KR)
[✓] Android toolchain - разработка для Android-устройств (версия Android SDK 34.0.0)
[✓] Xcode - разработка для iOS и macOS (Xcode 15.4)
[✓] Chrome - разработка для веба
[✓] Android Studio (версия 2024.1)
[✓] VS Code (версия 1.94.2)
[✓] VS Code (версия 1.91.1)
[✓] Сетевые ресурсы

Кто-нибудь может подсказать, где я ошибаюсь?

Ответ или решение

Ваша проблема с выполнением HTTP-запросов в приложении Flutter на новых устройствах Android, таких как Galaxy S23 Ultra и Galaxy S24+, действительно требует тщательного анализа. Давайте проанализируем ваш код и предложенные вами конфигурации, а также возможные неполадки и решения.

1. Проверка конфигурации сети

Вы указали, что добавили файл network_security_config.xml, который позволяет использование небезопасного трафика. Тем не менее, убедитесь, что используемый вами домен разрешен для небезопасного трафика:

<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">WW.XXX.YYY.ZZZ</domain>
    </domain-config>
</network-security-config>

Замените IP-адрес на доменное имя, которое используется в вашем URL (если оно доступно), это может устранить возможные проблемы с конфигурацией.

2. Проверка разрешений в манифесте

Вы добавили необходимое разрешение на интернет в вашем AndroidManifest.xml. Тем не менее, стоит обратить внимание на следующую особенность: начиная с Android 9 (API уровень 28), для работы с небезопасными (HTTP) запросами требуется явное разрешение. Проверьте, есть ли у вас следующая строка в манифесте:

<application
    ...
    android:usesCleartextTraffic="true">

Убедитесь, что данное разрешение остается для вашего приложения.

3. Обработка сетевых ошибок

Ваш метод register обрабатывает сетевые запросы, но возврат -1 при возникновении исключения не предоставляет достаточной информации о характере ошибки. Для лучшей отладки добавьте вывод сообщения об ошибке:

catch (e) {
    print("Ошибка во время HTTP запроса: $e");
    return -1;
}

4. Проверка сетевых условий

Убедитесь, что новые устройства имеют доступ к интернету и что они не используют настройки прокси или другие фильтры, которые могут блокировать HTTP-запросы. Также проверьте, нет ли дополнительных правил брандмауэра на стороне вашего сервера, которые могут блокировать запросы от новых устройств.

5. Логи и анализ запросов

Поскольку ваш бэкэнд не фиксирует никаких запросов, используйте инструменты для отладки, такие как Charles Proxy или Fiddler, которые позволят вам просмотреть трафик и понять, отправляются ли запросы и какие ответы (если таковые имеются) возвращаются.

6. Обновление зависимостей

Убедитесь, что все используемые вами пакеты (например, http и shared_preferences) обновлены до последних стабильных версий. Существование устаревших версий библиотек может привести к проблемам совместимости, особенно с новыми версиями ОС Android.

7. Протокол HTTPS

Если ваш API поддерживает HTTPS, обязательно используйте его вместо HTTP. Это не только повысит безопасность вашего приложения, но и может решить множество проблем совместимости с новыми версиями Android, которые более строги в отношении небезопасных соединений.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...