Используйте разные GoogleService-Info.plist для разных схем сборки


114

Я использую схему сборки для prod и одну для постановки (с двумя разными идентификаторами пакетов), и я пытаюсь использовать отдельный GoogleService-Info.plist для каждой схемы. Есть ли способ вручную выбрать файл plist для использования при инициализации GCM (и входа в систему goole)? Или можно не использовать plist и выполнить настройку вручную?

Спасибо!


3
Вы используете две разные цели? Затем поместите разные файлы (с одинаковыми именами) в разные ресурсы пакета копирования (которые находятся на этапах сборки).
Александр Зимин

6
Эта статья была для меня полезной medium.com/rocket-fuel/… .
Евгений

Отлично работал у меня stackoverflow.com/a/58709334/11537677
Knight Fighter

Ответы:


146

подробности

Проверено на:

  • Xcode 9.2
  • Xcode 10.2 (10E125)
  • Xcode 11.0 (11A420a)

Решение

  1. Создайте папку со всеми вашими файлами Google.plist (с разными именами) в проекте

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

  1. Добавить сценарий запуска

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

Не забудьте изменить значение PATH_TO_GOOGLE_PLISTS

Код

PATH_TO_GOOGLE_PLISTS="${PROJECT_DIR}/SM2/Application/Firebase"

case "${CONFIGURATION}" in

   "Debug_Staging" | "AdHoc_Staging" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info-dev.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

   "Debug_Poduction" | "AdHoc_Poduction" | "Distribution" | "Test_Poduction" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info-prod.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

    *)
        ;;
esac

Имена схем сборки

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


2
Спаси мой день отличный ответ
Сидд

1
Это правильный ответ. Очевидно, Firebase Analytics требует, чтобы этот файл plist находился в корневом каталоге вашего приложения, даже если вы вызываете configure(options:). github.com/firebase/quickstart-ios/issues/5
Роб Баджорек, 07

2
Это очень хорошее решение, и его следует принять как ответ.
Люк Брэндон Фаррелл

1
Очень легкий и умный, отличный ответ. Спасибо!
gabuchan

1
@smileBot, вы можете пропустить -r, подробнее: команда cp в Linux / Unix
Василий Боднарчук

76

Ответ @inidona сработал для меня. После того, как я преобразовал его в Swift

для Swift 2.3:

let filePath = NSBundle.mainBundle().pathForResource("GoogleService-Info", ofType: "plist")
let options = FIROptions(contentsOfFile: filePath)
FIRApp.configureWithOptions(options)

для Swift 3.0:

let filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!
let options = FIROptions(contentsOfFile: filePath)
FIRApp.configure(with: options)

для Swift 4.0:

let filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!
let options = FirebaseOptions(contentsOfFile: filePath)
FirebaseApp.configure(options: options!)

1
С помощью приведенного выше кода у вас есть два разных GoogleService-Info.plistфайла в разных местах или два файла с разными именами. Не могли бы вы предоставить дополнительную информацию о том, каковы настоящие имена файлов и где они находятся?
Варун Гупта,

1
У меня есть 2 файла с именем GoogleService-Info-dev.plist GoogleService-Info-live.plist, этот код позволяет вам сообщить вашему приложению, с каким файлом информации вы хотите работать вместо стандартного условного оператора GoogleService-Info-dev.plist или целевые флаги для
переключения

да, в AppDelegate
Эссам Элмасри

1
дает мне 'Не удалось найти файл конфигурации:' GoogleService-Info.plist ''
orium

В недавнем документе говорится: «Предупреждение: в некоторых случаях этот подход может повлиять на сбор данных Google
Шинго Фукуяма,

31

Проверьте эту статью: https://medium.com/@brunolemos/how-to-setup-a-different-firebase-project-for-debug-and-release-environments-157b40512164

В Xcode создайте внутри вашего проекта два каталога: Debugи Release. Положите GoogleService-Info.plistтуда каждый файл.

На AppDelegate.mвнутри didFinishLaunchingWithOptionsметода, поместите код:

Цель-C

  NSString *filePath;
#ifdef DEBUG
  NSLog(@"[FIREBASE] Development mode.");
  filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist" inDirectory:@"Debug"];
#else
  NSLog(@"[FIREBASE] Production mode.");
  filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist" inDirectory:@"Release"];
#endif

  FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
  [FIRApp configureWithOptions:options];

Swift 4

var filePath:String!
#if DEBUG
    print("[FIREBASE] Development mode.")
    filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist", inDirectory: "Debug")
#else
    print("[FIREBASE] Production mode.")
    filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist", inDirectory: "Release")
#endif

let options = FirebaseOptions.init(contentsOfFile: filePath)!
FirebaseApp.configure(options: options)

Перетащите обе папки Debugи в Releaseпапку Build Phases > Copy Bundle Resources:

Этапы сборки> Копировать ресурсы пакета

Это оно :)


1
Это сработало для меня. Вы должны добавить эти папки туда в качестве справки, иначе он действительно выйдет из строя. Спасибо!
Eironeia

Это решение по-прежнему не решает проблему для Analyticsфреймворка, вы не можете сказать, какой .plistименно загружается.
Lifely

@Bruno Lemos, Могу ли я одновременно использовать два проекта Firebase из одного проекта xcode? Не как Debug& Release? Потому что, когда я пытаюсь это сделать, я всегда already configured crash.получаю, что следую последней инструкции из официального документа Firebase. Спасибо
Тулон

24

Я думаю, вы можете использовать этот способ для динамической настройки вашего GoogleService-Info.plist и использовать разные имена для разных идентификаторов пакетов.

чао Андреас

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
[FIRApp configureWithOptions:options];

5
С помощью приведенного выше кода у вас есть два разных файла, файлы GoogleService-Info.plist в разных местах или два файла с разными именами. Не могли бы вы предоставить дополнительную информацию о том, каковы настоящие имена файлов и где они находятся?
Варун Гупта,

4
Я получаю эту ошибку в журнале во время вызова configureWithOptions:Could not locate configuration file: 'GoogleService-Info.plist'
Бабкен Варданян

14

Я заметил, что Google ожидает, что имя файла будет GoogleServiceInfo.plist в коде:

 * The method |configureWithError:| will read from the file GoogleServices-Info.plist bundled with
 * your app target for the keys to configure each individual API. To generate your
 * GoogleServices-Info.plist, please go to https://developers.google.com/mobile/add
 *
 * @see GGLContext (Analytics)
 * @see GGLContext (SignIn)
 */
@interface GGLContext : NSObject

ключевая фраза эта

читать из файла GoogleServices-Info.plist, связанного с вашим целевым приложением

Поэтому я просто скопировал один и тот же файл, поместил его в разные каталоги и привязал его к разным целям:

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


Спасибо, очень просто и отлично работает для меня, Xcode 10.1, FirebaseCore (5.3.1)
infinity_coding7

Как избежать ошибки "Создание нескольких команд", которая возникает из-за нескольких файлов Plist или других файлов в приложении
Вахаб Хан

12

Если у GoogleService-Info.plistнего другое имя, это повлияет на результаты вашей аналитики. Firebase предупредит вас об этом. https://github.com/firebase/firebase-ios-sdk/issues/230#issuecomment-327138180 . По этой причине ни одно из этих runtime-решений не обеспечит наилучших результатов аналитики.

Есть два решения, которые не повлияют на Google Analytics.

  1. Используйте разные цели для каждой схемы и свяжите каждую версию GoogleService-Info.plistс собственной целью. См. Целевое членство в инспекторе файлов справа в Xcode. Для получения дополнительной информации см. Этот вопрос .

  2. Использование фазы сборки сценария , чтобы скопировать правильную версию из GoogleService-Info.plistв каталог сборки. Я использую другой идентификатор пакета для постановки и производства. Это позволяет мне устанавливать обе версии приложения параллельно. Это также означает, что с помощью приведенного ниже сценария я могу называть свои различные GoogleService-Info.plistфайлы идентификатором пакета. Например:

    • GoogleService-Info-com.example.app.plist
    • GoogleService-Info-com.example.app.staging.plist

Скрипт этапа сборки

PATH_TO_CONFIG=$SRCROOT/Config/GoogleService-Info-$PRODUCT_BUNDLE_IDENTIFIER.plist
FILENAME_IN_BUNDLE=GoogleService-Info.plist
BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo cp $PATH_TO_CONFIG "$BUILD_APP_DIR/$FILENAME_IN_BUNDLE"
cp $PATH_TO_CONFIG "$BUILD_APP_DIR/$FILENAME_IN_BUNDLE"

Примечание. Вам нужно будет изменить PATH_TO_CONFIGнастройки в соответствии с вашими требованиями.

Скрипт этапа сборки


1
На данный момент это лучшее решение. Поскольку Firebase Crashlytics может использовать только файл GoogleService-Info.plist для загрузки файлов dSYM с помощью скрипта upload-symbols - это решение отлично работает!
Алексей Галишников

7

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

Шаг 1.
Скопируйте GoogleService-Info.plist, соответствующий вашей среде разработки Firebase, в каталог Dev . Точно так же скопируйте GoogleService-Info.plist, соответствующий вашей производственной среде Firebase, в каталог Prod . Обязательно снимите флажок «Копировать элементы, если необходимо» и все цели в разделе «Добавить в цели» .

(Шаг 1 ссылка на изображение (я не могу добавить изображение из-за меньшей репутации))

Шаг 2.
В навигаторе проекта Xcode выберите цель приложения. Переключитесь на вкладку Build Phases вверху, затем добавьте New Run Script Phase . Назовите этап «Настройка Firebase Environment GoogleService-Info.plist» или что-нибудь в этом роде и поместите его перед этапом «Копировать ресурсы пакета» .

Шаг 3. Реализуйте
сценарий оболочки, который скопирует соответствующий GoogleService-Info.plist в пакет приложения на основе конфигурации сборки. Скопируйте и вставьте следующий сценарий оболочки в только что созданный этап сценария выполнения:

# Name of the resource we're selectively copying
GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist

# Get references to dev and prod versions of the GoogleService-Info.plist
# NOTE: These should only live on the file system and should NOT be part of the target (since we'll be adding them to the target manually)
GOOGLESERVICE_INFO_DEV=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Dev/${GOOGLESERVICE_INFO_PLIST}
GOOGLESERVICE_INFO_PROD=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Prod/${GOOGLESERVICE_INFO_PLIST}

# Make sure the dev version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_DEV}"
if [ ! -f $GOOGLESERVICE_INFO_DEV ]
then
    echo "No Development GoogleService-Info.plist found. Please ensure it's in the proper directory."
    exit 1
fi

# Make sure the prod version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_PROD}"
if [ ! -f $GOOGLESERVICE_INFO_PROD ]
then
    echo "No Production GoogleService-Info.plist found. Please ensure it's in the proper directory."
    exit 1
fi

# Get a reference to the destination location for the GoogleService-Info.plist
PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${PLIST_DESTINATION}"

# Copy over the prod GoogleService-Info.plist for Release builds
if [ "${CONFIGURATION}" == "Release" ]
then
    echo "Using ${GOOGLESERVICE_INFO_PROD}"
    cp "${GOOGLESERVICE_INFO_PROD}" "${PLIST_DESTINATION}"
else
    echo "Using ${GOOGLESERVICE_INFO_DEV}"
    cp "${GOOGLESERVICE_INFO_DEV}" "${PLIST_DESTINATION}"
fi

6

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

GoogleService-Info_stage.plist

и

GoogleService-Info_prod.plist

Затем из вашего кода вы можете вызвать правильный файл. Это не приведет к сбою вашего приложения, если у вас нет файла. Просто замените FILENAME на GoogleService-Info_prod или GoogleService-Info_stage.

if let configFile = Bundle.main.path(forResource: "FILENAME", ofType: "plist"), 
    let options = FirebaseOptions(contentsOfFile: configFile)   
{
   FirebaseApp.configure(options: options)
}

Конфигурации среды выполнения могут привести к проблемам с отчетами аналитики, как указано в документации .
Alex

3

Это моё решение!

NSString *filePath;
if([self isProduction]){
    filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
}else{
    filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info-Sandbox" ofType:@"plist"];
}
FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
[FIRApp configureWithOptions:options];

И это все!


3

Этот ответ очень вдохновлен @abbood , но немного более конкретным о том, как это сделать.

Для каждой из ваших целей, например dev, stg, prod:

  • Загрузите соответствующий GoogleService-Info.plist файл в отдельную папку с именем вашей цели
  • В Xcode щелкните правой кнопкой мыши папку приложения и выберите Add files to "your app" введите описание изображения здесь
  • Выберите папку, содержащую цели GoogleService-Info.plist, убедитесь, что Copy items if neededи Create groupsвыбраны, отметьте только соответствующую цель в списке целей и нажмитеAdd введите описание изображения здесь

Вот и все. Теперь у вас должно получиться что-то похожее на эту структуру

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

При построении мишени GoogleService-Info.plistбудет использоваться правильный .


У меня отлично сработало.
afak Gezer,

2

Вот как это сделать в Xamarin C #:

string plistPath = NSBundle.MainBundle.PathForResource ("GoogleService-Info", "plist");
Options options = new Options (plistPath);
App.Configure (options);

Не забудьте включить пространство имен Firebase:

using Firebase.Analytics;

1

Я думаю, что этого невозможно достичь без использования GoogleService-Info.plist.Потому что, прежде чем вы сможете начать интеграцию своего приложения iOS с компонентами входа в Google, вы должны загрузить зависимости и настроить свой проект Xcode. И этот процесс показывает, чтоGoogleService-Info.plist имеет большое значение.

Итак, решения и идея здесь, в этом вопросе SO, могут помочь вам с вашей проблемой. Просто переместили основную копиюGoogleService-Info plist из приложения в 2 отдельные папки, а затем использовал этапы сборки «Копировать файлы» для каждой цели, чтобы импортировать целевой файл plist в папку «Ресурсы».

Также проверьте этот вопрос SO , он может дать вам дополнительную информацию / идею по вашей проблеме.


Здесь цель означает другую схему для одного и того же проекта? Прочитав вопросы, я понял, что цель означает совсем другую цель сборки, а не просто другую схему сборки для той же цели.
Варун Гупта,

1
Но что, если у вас есть одна цель с разной конфигурацией для каждой схемы?
evya

1

В Xcode 9.2 мне нужны файлы для обеих целей, которые должны называться "googleServiceInfo.plist", но размещаться в разных каталогах, причем каталог / файл для каждой цели указан в "Фазы сборки", "Копировать ресурсы пакета".

Вышеупомянутое не было моим предпочтительным решением, но я ранее пробовал использовать разные имена файлов в строках ответа @inidona, преобразованного в Swift 4:

 let filePath = Bundle.main.path(forResource: "googleServiceInfo-Pro", ofType: "plist")!
 let options = FirebaseOptions(contentsOfFile: filePath)
 FirebaseApp.configure(options: options!)

К сожалению, это не помогло исправить сообщения об ошибках Firebase. В этом вопросе: Firebase iOS SDK - использование файла конфигурации, отличного от GoogleService-Info.plist, генерирует предупреждение консоли, которое, похоже, исправлено исходным плакатом путем обновления Firebase Pod, но я не подтвердил это.


1

Я решил это следующим образом:

    #if STAGING
        if let filePath = Bundle.main.path(forResource: "GoogleService-Info-Dev", ofType: "plist"),
            let options = FirebaseOptions(contentsOfFile: filePath) {
                FirebaseApp.configure(options: options)
        } else {
            fatalError("GoogleService-Info-Dev.plist is missing!")
        }
    #else
        if let filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist"),
            let options = FirebaseOptions(contentsOfFile: filePath) {
                FirebaseApp.configure(options: options)
        } else {
            fatalError("GoogleService-Info.plist is missing!")
        }
    #endif

1

Если кто-то из вас попадает в ошибку и Xcode жалуется

"Несколько команд создают GoogleService-Info.plist"

после применения ответа @Knight Fighter вы можете:

  • Проверьте этапы сборки> Копировать ресурсы пакета
  • Фильтр для файлов с именем GoogleService-Info.plist
  • Удалите все ссылки на него, поскольку они уже копируются через скрипт.

0

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

Я придумал расширяемое решение, которое копирует GoogleSerives-Info.plistфайл во время сборки. Более того, этот подход может поддерживать столько сред, сколько вам нужно, с возможностью настройки и соблюдением простых соглашений, что упрощает управление.

Прежде всего, у меня есть три среды: debug(для работы в симуляторе и отладки устройства и активной резки кода), staging(для развертывания в тестовом полете) иrelease для производства.

Шаг первый - создать вашу конфигурацию (ы):

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

Выберите «Продукт» -> «Схема» -> «Изменить схему» и продублируйте / создайте новую по мере необходимости. Просмотрите каждую схему и назначьте ей соответствующую конфигурацию из раскрывающегося списка «Конфигурация сборки» в каждой из категорий:

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

Я делаю еще один шаг и снимаю отметку с «запускать» для схем, которые необходимо распространить, т.е. выпуск и постановка, и, наоборот, снимаю отметку с «архив» для отладки. Вы должны делать то, что имеет для вас смысл.

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

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

# Get a reference to the folder which contains the configuration subfolders.
CONFIGURATIONS_FOLDER=Firebase
# Get a refernce to the filename of a 'GoogleService-Info.plist' file.
GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist
# Get a reference to the 'GoogleService-Info.plist' for the current configuration.
GOOGLESERVICE_INFO_PLIST_LOCATION=${PROJECT_DIR}/${TARGET_NAME}/${CONFIGURATIONS_FOLDER}/${CONFIGURATION}/${GOOGLESERVICE_INFO_PLIST}
# Check if 'GoogleService-Info.plist' file for current configuration exist.
if [ ! -f $GOOGLESERVICE_INFO_PLIST_LOCATION ]
then
  echo "No '${GOOGLESERVICE_INFO_PLIST}' file found for the configuration '${CONFIGURATION}' in the configuration directory '${PROJECT_DIR}/${TARGET_NAME}/${CONFIGURATIONS_FOLDER}/${CONFIGURATION}'."
  exit 1
fi
# Get a reference to the destination location for the GoogleService-Info.plist.
GOOGLESERVICE_INFO_PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
# Copy 'GoogleService-Info.plist' for current configution to destination.
cp "${GOOGLESERVICE_INFO_PLIST_LOCATION}" "${GOOGLESERVICE_INFO_PLIST_DESTINATION}"
echo "Successfully coppied the '${GOOGLESERVICE_INFO_PLIST}' file for the '${CONFIGURATION}' configuration from '${GOOGLESERVICE_INFO_PLIST_LOCATION}' to '${GOOGLESERVICE_INFO_PLIST_DESTINATION}'."

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

В выбранной вами папке конфигураций («Firebase» в приведенном выше примере) вложите папки для каждой конфигурации, названной точно так же, как ее соответствующая конфигурация (с учетом регистра), внутри которых поместите соответствующие GoogleServices-Info.plistфайлы следующим образом:

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

И последнее, но не менее важное: я также хотел бы убедиться, что корневой уровень GoogleServices-Info.plistне добавлен в проект случайно, поэтому я добавляю следующее в свой .gitignore.

# Ignore project level GoogleService-Info.plist
/[Project Name]/GoogleService-Info.plist

0

Предположим, у нас есть две конфигурации, developи production. Вам нужно сделать две вещи:

  1. Переименуйте оба списка в соответствии с заданной конфигурацией:
  • GoogleService-Info-develop.plist
  • GoogleService-Info-production.plist
  1. Добавьте сценарий запуска, который копирует правильный список для выбранной конфигурации:
FIREBASE_PLIST_PATH="${PROJECT_DIR}/App/Resources/Plists/GoogleService-Info-${CONFIGURATION}.plist"
echo "Firebase plist path: ${FIREBASE_PLIST_PATH}"
cp -r ${FIREBASE_PLIST_PATH} "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"

Сценарий выполнения должен быть размещен перед FirebaseCrashlytics сценарием.

Вы можете запустить firebase, как и раньше, для одной схемы: FirebaseApp.configure()

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.