Google-services.json для разных продуктовFlavors

Update: GCM is deprecated, use FCM

Я внедряю новый Google Cloud Messaging, следуя инструкциям на странице разработчиков Google здесь

Я успешно запустил и протестировал его. Но моя проблема сейчас в том, что у меня разные варианты продукта с разными applicationId/packageName и разными идентификаторами проекта Google Cloud Messaging Project. google-services.json должен быть помещен в /app/google-services.json, а не в папку flavors.

Есть ли способ сделать конфиг google-services.json разным для разных вкусов?

+426
источник поделиться
25 ответов

Google включил поддержку ароматов в версию 2.0 плагина сервисов воспроизведения. Начиная с этой версии gradle plugin com.google.gms:google-services:2.0.0-alpha3

Вы можете сделать это

app/src/
    flavor1/google-services.json
    flavor2/google-services.json

Плагин версии 3.0.0 ищет файл json в этих местах (учитывая, что у вас есть flavor flav1 и тип сборки debug):

/app/src/debug/google-services.json
/app/src/debug/flavor1/google-services.json
/app/google-services.json

Это сработало для меня даже с использованием flavourDimensions. У меня есть бесплатные & оплачивается в одном измерении и макет & Прод в другом измерении. У меня также есть 3 buildTypes: отладка, выпуск и постановка. Вот как это выглядит в моем проекте для аромата FreeProd:

enter image description here

Сколько файлов google-services.json будет зависеть от характеристик вашего проекта, но вам потребуется как минимум один файл json для каждого проекта Google.

Если вы хотите узнать больше о том, что этот плагин делает с этими файлами json, вот оно: https://github.com/googlesamples/google-services/issues/54#issuecomment-165824720

Ссылка на официальные документы: https://developers.google.com/android/guides/google-services-plugin

Сообщение в блоге с обновленной информацией: https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html

И перейдите сюда, чтобы проверить последнюю версию этого плагина: https://bintray.com/android/android-tools/com.google.gms.google-services/view

+474
источник

ОБНОВЛЕНИЕ: Ниже приведено объяснение для одного проекта Android Studio с одним проектом Firebase и различными Firebase Apps внутри этого проекта. Если цель состоит в том, чтобы иметь разные файлы JSON для разных приложений Firebase в разных проектах Firebase внутри одного и того же проекта Android Studio (или если вы не знаете, в чем разница) смотрите здесь.

Вам нужно одно приложение Firebase для Android-приложения (обычно это имя пакета). Обычно имеет один идентификатор приложения для варианта сборки Gradle (это будет вероятно, если вы используете типы сборки Gradle и Gradle).


Как и в Google Services 3.0 и используя Firebase, нет необходимости создавать разные файлы для разных вкусов. Создание разных файлов для разных вкусов может быть непонятным или простым в том случае, если у вас есть productFlavours и типы сборки, которые составляют друг с другом.

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

В консоли Firebase вам нужно добавить одно приложение для имени пакета. Представьте, что у вас есть 2 аромата (dev и live) и 2 типа сборки (отладка и выпуск). В зависимости от вашей конфигурации, но, вероятно, у вас есть 4 разных имени пакета, например:

  • com.stackoverflow.example(live-release)
  • com.stackoverflow.example.dev(live-dev)
  • com.stackoverflow.example.debug(debug-release)
  • com.stackoverflow.example.dev.debug(debug-dev)

Вам нужно 4 различных приложения для Android в Firebase Console. (Для каждого из них вам нужно добавить SHA-1 для отладки и жить для каждого компьютера, который вы используете)

Когда вы загружаете файл google-services.json, на самом деле это не имеет никакого значения, из какого приложения вы его загружаете, все они содержат одну и ту же информацию, связанную со всеми вашими приложениями.

Теперь вам нужно найти этот файл на уровне приложения (app/).

введите описание изображения здесь

Если вы откроете этот файл, вы увидите, что if содержит всю информацию для всех ваших имен пакетов.

Больной точкой является плагин. Чтобы получить работу, вам нужно найти плагин в нижней части файла. Итак, эта строка..

apply plugin: 'com.google.gms.google-services'

... должен быть в нижней части вашего файла build.gradle приложения.

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

+63
источник
другие ответы

Связанные вопросы


Похожие вопросы

Написал средний пост по этой проблеме.

Если бы подобная проблема (с использованием BuildTypes вместо Flavors) и исправлена ​​так.

Воспользуйтесь системой управления зависимостями Gradle. Я создал две задачи: switchToDebug и switchToRelease. Требовать, чтобы выполнялось любое время assembleRelease, также запускается switchToRelease. То же самое для отладки.

def appModuleRootFolder = '.'
def srcDir = 'src'
def googleServicesJson = 'google-services.json'

task switchToDebug(type: Copy) {
    def buildType = 'debug'
    description = 'Switches to DEBUG google-services.json'
    from "${srcDir}/${buildType}"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

task switchToRelease(type: Copy) {
    def buildType = 'release'
    description = 'Switches to RELEASE google-services.json'
    from "${srcDir}/${buildType}/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

afterEvaluate {
    processDebugGoogleServices.dependsOn switchToDebug
    processReleaseGoogleServices.dependsOn switchToRelease
}

РЕДАКТИРОВАТЬ: используйте задачу processDebugFlavorGoogleServices/processReleaseFlavorGoogleServices, чтобы изменить ее на уровне каждого уровня.

+40
источник

Ну, я столкнулся с той же проблемой и не смог найти идеального решения. Это просто обходной путь. Мне интересно, как Google не думал о вкусах...? И я надеюсь, что они вскоре предложит лучшее решение.

Что я делаю:

У меня есть два варианта: в каждом я помещаю соответствующие google-services.json: src/flavor1/google-services.json и src/flavor2/google-services.json.

Затем в build gradle я копирую файл в зависимости от вкуса в каталоге app/:

android {

// set build flavor here to get the right gcm configuration.
//def myFlavor = "flavor1"
def myFlavor = "flavor2"

if (myFlavor.equals("flavor1")) {
    println "--> flavor1 copy!"
    copy {
        from 'src/flavor1/'
        include '*.json'
        into '.'
    }
} else {
    println "--> flavor2 copy!"
    copy {
        from 'src/flavor2/'
        include '*.json'
        into '.'
    }
}

// other stuff
}

Ограничение: вам придется вручную менять myFlavor в gradle каждый раз, когда вы хотите запустить другой вкус (потому что он жестко запрограммирован).

Я пробовал много способов получить текущий аромат сборки, например, afterEvaluate close... не смог найти лучшего решения до сих пор.

Обновление, другое решение: один google-services.json для всех вариантов:

Вы также можете иметь разные имена пакетов для каждого аромата, а затем в консоли разработчика Google вам не нужно создавать два разных приложения для каждого аромата, но только два разных клиента в одном приложении. Тогда у вас будет только один google-services.json, содержащий ваших обоих клиентов. Конечно, это зависит от того, как вы реализуете бэкэнд своих вкусов. Если они не разделены, это решение вам не поможет.

+13
источник

В соответствии с ответом ahmed_khan_89 вы можете поставить "код копирования" внутри продукта.

productFlavors {
    staging {
        applicationId = "com.demo.staging"

        println "Using Staging google-service.json"
        copy {
            from 'src/staging/'
            include '*.json'
            into '.'
        }
    }
    production {
        applicationId = "com.demo.production"

        println "Using Production google-service.json"
        copy {
            from 'src/production/'
            include '*.json'
            into '.'
        }
    }
}

Затем вам не нужно вручную переключаться с настройками.

+12
источник

Файл google-services.json не требуется для получения уведомлений. Просто добавьте переменную для каждого аромата в файле build.gradle:

buildConfigField "String", "GCM_SENDER_ID", "\"111111111111\""

Используйте эту переменную BuildConfig.GCM_SENDER_ID вместо getString (R.string.gcm_defaultSenderId) при регистрации:

instanceID.getToken(BuildConfig.GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
+8
источник

Я использую файл google-services.json, созданный здесь: https://developers.google.com/mobile/add?platform=android&cntapi=gcm&cnturl=https:%2F%2Fdevelopers.google.com%2Fcloud-messaging%2Fandroid%2Fclient&cntlbl=Continue%20Adding%20GCM%20Support&%3Fconfigured%3Dtrue

В JSON-структуре есть JSON-массив, называемый клиентами. Если у вас несколько вариантов, просто добавьте здесь различные свойства.

{
  "project_info": {
    "project_id": "PRODJECT-ID",
    "project_number": "PROJECT-NUMBER",
    "name": "APPLICATION-NAME"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:PROJECT-NUMBER:android:HASH-FOR-FLAVOR1",
        "client_id": "android:PACKAGE-NAME-1",
        "client_type": 1,
        "android_client_info": {
          "package_name": "PACKAGE-NAME-1"
        }
      },
      "oauth_client": [],
      "api_key": [],
      "services": {
        "analytics_service": {
          "status": 1
        },
        "cloud_messaging_service": {
          "status": 2,
          "apns_config": []
        },
        "appinvite_service": {
          "status": 1,
          "other_platform_oauth_client": []
        },
        "google_signin_service": {
          "status": 1
        },
        "ads_service": {
          "status": 1
        }
      }
    },
    {
      "client_info": {
        "mobilesdk_app_id": "1:PROJECT-NUMBER:android:HASH-FOR-FLAVOR2",
        "client_id": "android:PACKAGE-NAME-2",
        "client_type": 1,
        "android_client_info": {
          "package_name": "PACKAGE-NAME-2"
        }
      },
      "oauth_client": [],
      "api_key": [],
      "services": {
        "analytics_service": {
          "status": 1
        },
        "cloud_messaging_service": {
          "status": 2,
          "apns_config": []
        },
        "appinvite_service": {
          "status": 1,
          "other_platform_oauth_client": []
        },
        "google_signin_service": {
          "status": 1
        },
        "ads_service": {
          "status": 1
        }
      }
    }
  ],
  "client_info": [],
  "ARTIFACT_VERSION": "1"
}

В моем проекте я использую один и тот же идентификатор проекта, и когда я добавляю второе имя пакета в указанном выше URL, google предоставляет мне файл, содержащий несколько клиентов в json-данных.

Извините за компактные JSON-данные. Я не смог правильно отформатировать его...

+8
источник

1.) Что делает google-services.json действительно?

Следуйте этому следующему: fooobar.com/questions/39666/...

2.) Как файл google-services.json влияет на ваш проект студии Android?

Следуйте этому: fooobar.com/questions/39666/...

вкратце для второго URL-адреса, если вы добавите google-services.json в свой проект, в этом пути должна быть создана сгенерированная автоматически google-services папка для debug.

app/build/generated/res/google-services/debug/values/values.xml

3.) Что делать, чтобы сделать это?

добавьте зависимость google-services в project_level build.gradle, вы также можете использовать version 3.0.0, если используете библиотеку app_compact.

// Top-level build.gradle file
classpath 'com.google.gms:google-services:2.1.2'

теперь в app_level build.gradle вы должны добавить внизу.

// app-level build.gradle file
apply plugin: 'com.google.gms.google-services'

4.) Куда поместить файл google-service.json в вашу структуру.

case 1.), если у вас нет build_flavor, просто поместите его внутри папки /app/google-service.json.

case 2.), если у вас есть несколько build_flavor, и у вас есть разные файлы google_services.json, помещенные внутри app/src/build_flavor/google-service.json.

case 3.), если у вас есть несколько build_flavor, и у вас есть один файл google_services.json, помещенный внутри app/google-service.json.

+6
источник

ОБНОВЛЕНО:

С точки зрения настройки Firebase с вариантами сборки, пожалуйста, обратитесь к этому блогу, в котором есть подробные инструкции.

+4
источник

У нас есть другое имя пакета для отладочных сборников (*.debug), поэтому я хотел что-то, что работает на основе flavor и buildType, без необходимости писать что-либо, связанное с ароматом, в шаблоне processDebugFlavorGoogleServices.

В каждом аромате я создал папку с именем "google-services", содержащую как версию отладки, так и версию выпуска json файла:

введите описание изображения здесь

В разделе buildTypes вашего файла gradle добавьте следующее:

    applicationVariants.all { variant ->
            def buildTypeName = variant.buildType.name
            def flavorName = variant.productFlavors[0].name;

            def googleServicesJson = 'google-services.json'
            def originalPath = "src/$flavorName/google-services/$buildTypeName/$googleServicesJson"
            def destPath = "."

            copy {
                if (flavorName.equals(getCurrentFlavor()) && buildTypeName.equals(getCurrentBuildType())) {
                    println originalPath
                    from originalPath
                    println destPath
                    into destPath
                }
            }
    }

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

Добавьте два метода, которые вызывают, чтобы получить текущий тип и текущий тип сборки в корне вашего build.gradle

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() ) {
        println matcher.group(1).toLowerCase()
        return matcher.group(1).toLowerCase()
    }
    else
    {
        println "NO MATCH FOUND"
        return "";
    }
}

def getCurrentBuildType() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

        if (tskReqStr.contains("Release")) {
            println "getCurrentBuildType release"
            return "release"
        }
        else if (tskReqStr.contains("Debug")) {
            println "getCurrentBuildType debug"
            return "debug"
        }

    println "NO MATCH FOUND"
    return "";
}

Для этого вам не нужно беспокоиться об удалении/добавлении/изменении вкусов из вашего файла gradle, и он автоматически отлаживает или выпускает google-services.json.

+4
источник

Firebase теперь поддерживает несколько идентификаторов приложений с одним файлом google-services.json.

Это сообщение в блоге подробно описывает его.

Вы создадите один родительский проект в Firebase, который вы будете использовать для всех ваших вариантов. Затем вы создаете отдельные приложения для Android в Firebase в рамках этого проекта для каждого вашего идентификатора приложения.

Когда вы создали все свои варианты, вы можете загрузить google-services.json, который поддерживает все ваши идентификаторы приложений. Когда это имеет значение для просмотра данных отдельно (т.е. Crash Reporting), вы можете переключаться с раскрывающимся списком.

+4
источник

Основываясь на ответе @ZakTaccardi и предполагая, что вам не нужен один проект для обоих вариантов, добавьте его в конец вашего файла build.gradle:

def appModuleRootFolder = '.'
def srcDir = 'src'
def googleServicesJson = 'google-services.json'

task switchToStaging(type: Copy) {
    outputs.upToDateWhen { false }
    def flavor = 'staging'
    description = "Switches to $flavor $googleServicesJson"
    delete "$appModuleRootFolder/$googleServicesJson"
    from "${srcDir}/$flavor/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

task switchToProduction(type: Copy) {
    outputs.upToDateWhen { false }
    def flavor = 'production'
    description = "Switches to $flavor $googleServicesJson"
    from "${srcDir}/$flavor/"
    include "$googleServicesJson"
    into "$appModuleRootFolder"
}

afterEvaluate {
    processStagingDebugGoogleServices.dependsOn switchToStaging
    processStagingReleaseGoogleServices.dependsOn switchToStaging
    processProductionDebugGoogleServices.dependsOn switchToProduction
    processProductionReleaseGoogleServices.dependsOn switchToProduction
}

Вам нужны файлы src/staging/google-services.json и src/production/google-services.json. Замените имена аромата для тех, которые вы используете.

+3
источник

Я обнаружил, что плагин google-services совершенно бесполезен для проектов, которые хотят добавить GCM. Он генерирует только следующий файл, который просто добавляет ваш идентификатор проекта в виде строкового ресурса:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Your API key would be on the following line -->
    <string name="gcm_defaultSenderId">111111111111</string>
</resources>

Кажется, что вам это нужно только в том случае, если вы скопировали образец кода дословно из руководства Cloud Messaging for Android. Вот пример строки:

String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),              GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

Решение

Если вы хотите иметь возможность переключать проекты API для разных типов сборки или продуктов, вы можете просто определить свои собственные константы и выбрать подходящий при вызове API getToken().

private static final String SENDER_ID = "111111111111";
private static final String SANDBOX_SENDER_ID = "222222222222";

String token = instanceID.getToken(
        BuildConfig.DEBUG ? SENDER_ID : SANDBOX_SENDER_ID,
        GoogleCloudMessaging.INSTANCE_ID_SCOPE,
        null);

Для ароматов продукта

Приведенный выше код работает для переключения между сборками отладки и выпуска. Для вкусов продукта вы должны определить разные ключи API в исходном файле java и поместить файлы в соответствующий каталог продуктов. Для справки: Gradle Варианты сборки

+3
источник

Нет необходимости в дополнительных скриптах gradle.

Google начал добавлять разные имена пакетов под именем "android_client_info". Он выглядит ниже в google-services.json

"android_client_info": {
      "package_name": "com.android.app.companion.dev"
    }

поэтому для выполнения разных вариантов google-services.json достаточно выполнить следующие шаги.

  • Есть 2 аромата
  • Добавьте новый пакет аромата dev на страницу конфигурации Google Analytics и загрузите google-services.json.
  • Обратите внимание, что в новом файле конфигурации есть оба идентификатора пакета аромата.
  • Подготовьте любой из ваших ароматов.

Вот и все!..

+3
источник

Точка плагина google-services предназначена для упрощения интеграции функций Google.

Поскольку он генерирует только андроидные ресурсы из файла google-services.json, чрезмерный сложный gradle -logic отрицает этот момент, я думаю.

Итак, если Google-документы не говорят, какие ресурсы необходимы для определенных функций Google, я бы предложил создать JSON файл для каждого соответствующего типа buildtype/flavor, посмотреть, какие ресурсы будут генерироваться плагином, а затем разместить эти ресурсы вручную в соответствующие каталоги src/buildtypeORflavor/res.

После этого удалите ссылки на плагин google-services и JSON файл, и все готово.

Для получения подробной информации о внутренней работе google-services gradle -plugin см. мой другой ответ:

fooobar.com/questions/39666/...

+2
источник

Упрощение того, что сказал @Scotti. Вам необходимо создать приложения Multiples с различным именем пакета для конкретного проекта в зависимости от вкуса продукта.

Предположим, что у вашего проекта есть ABC с разными вкусами продукта X, Y, где X имеет имя пакета com.x, а Y имеет имя пакета com.y, тогда в консоли firebase вам необходимо создать проект ABC, в котором вам нужно создать 2 приложения с именами пакетов com.x и com.y. Затем вам нужно загрузить файл google-services.json, в котором будет два объекта-клиент-информация, которые будут содержать эти pacakges, и вам будет хорошо идти.

Фрагмент json будет примерно таким

{
  "client": [
    {
      "client_info": {
        "android_client_info": {
          "package_name": "com.x"
        }

    {
      "client_info": {
        "android_client_info": {
          "package_name": "com.y"
        }
      ]

    }
+2
источник

У вас много вкуса, так что это означает, что у вас будет много разного идентификатора пакета, верно? Итак, просто зайдите на страницу, где вы настраиваете/генерируете свой json файл и конфигурацию для каждого имени пакета. Все это добавит json файл.

Теперь я не буду лениво размещать картинку, но в основном:

  • перейти к https://developers.google.com/mobile/add
  • выберите платформу
  • выберите ваше приложение.
  • ВАЖНО: введите имя пакета аромата в поле "имя пакета Android"
  • ... продолжаем получать ваш файл конфигурации. Загрузите его!

При настройке файла вы увидите, что Google показывает вам идентификатор сервера + идентификатор отправителя. И он одинаковый для всех пакетов (ароматов)

В конце вам нужен всего один файл json для всех вкусов.

Еще один вопрос, который вы должны проверить, когда регистрируетесь, чтобы получить регистрационный токен, проверьте, есть ли разница для каждого аромата. Я не касаюсь этого, но думаю, что это должно быть различие. Слишком поздно, и я так сонный:) Надеюсь, это поможет!

+1
источник

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

+1
источник

Действительно, juste one google-services.json в каталоге MyApp/app/ хорош, нет необходимости в дополнительном script с com.google.gms:google-services:3.0.0. Но будьте осторожны, чтобы удалить файл google-services.json из каталога приложений MyApp/app/src/flavor1/res/, чтобы избежать типа ошибки Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package

+1
источник

Так что если вы хотите программно скопировать файл google-services.json из всех ваших вариантов в вашу корневую папку. Когда вы переключаетесь на конкретный вариант, здесь решение для вас

android {
  applicationVariants.all { variant ->
    copy {
        println "Switches to $variant google-services.json"
        from "src/$variant"
        include "google-services.json"
        into "."
    }
  }
}

Есть предостережение в отношении этого подхода: вам нужно иметь файл google-service.json в каждой папке с вариантами, вот пример. variant image

+1
источник

В настоящее время я использую два идентификатора проекта GCM в том же пакете приложений. Я поместил google-service.json из моего первого проекта GCM, но переключился с первого на второй, только меняя SENDER_ID:

    String token = instanceID.getToken(SENDER_ID,GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

(В этот момент я думаю, что google-services.json не является обязательным)

0
источник

Вдохновленный @ahmed_khan_89 ответом выше. Мы можем напрямую хранить это в файле gradle.

android{

// set build flavor here to get the right Google-services configuration(Google Analytics).
    def currentFlavor = "free" //This should match with Build Variant selection. free/paidFull/paidBasic

    println "--> $currentFlavor copy!"
    copy {
        from "src/$currentFlavor/"
        include 'google-services.json'
        into '.'
    }
//other stuff
}
0
источник

Поместите файл "google-services.json" в папку app/src/flavors соответственно затем в build.gradle приложения, под android добавьте ниже код

gradle.taskGraph.beforeTask { Task task ->
        if (task.name ==~ /process.*GoogleServices/) {
            android.applicationVariants.all { variant ->
                if (task.name ==~ /(?i)process${variant.name}GoogleServices/) {
                    copy {
                        from "/src/${variant.flavorName}"
                        into '.'
                        include 'google-services.json'
                    }
                }
            }
        }
    }
0
источник

Согласно Документам Firebase вы также можете использовать строковые ресурсы вместо google-services.json.

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

  • Удаление плагина google-services из корневого каталога build.gradle
  • Удаление google-services.json из вашего проекта
  • Добавление строковых ресурсов напрямую
  • Удаление подключаемого модуля: 'com.google.gms.google-services' из вашего приложения build.gradle

Пример strings.xml:

<string name="google_client_id">XXXXXXXXX.apps.googleusercontent.com</string>
<string name="default_web_client_id">XXXX-XXXXXX.apps.googleusercontent.com</string>
<string name="gcm_defaultSenderId">XXXXXX</string>
<string name="google_api_key">AIzaXXXXXX</string>
<string name="google_app_id">1:XXXXXX:android:XXXXX</string>
<string name="google_crash_reporting_api_key">AIzaXXXXXXX</string>
<string name="project_id">XXXXXXX</string>
0
источник

Здравствуйте! google.com Попробуйте поискать в Google, это поможет!

-2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос