对不同的构建方案使用不同的GoogleService-Info.plist

nwa*_*gui 78 ios google-cloud-messaging google-signin

我正在使用prod的构建方案和一个用于暂存的构建方案(具有2个不同的bundle标识符),我正在尝试为每个方案使用单独的GoogleService-Info.plist.在初始化GCM(和goole登录)时,有没有办法手动选择要使用的plist文件?或者是否可以避免使用plist并手动进行设置?

谢谢!

Vas*_*huk 87

细节

Xcode 9.2

  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
Run Code Online (Sandbox Code Playgroud)

构建方案名称

在此输入图像描述

  • 这是正确的答案。显然,Firebase Analytics 要求您的应用程序根目录中存在该 plist 文件,即使您调用“configure(options:)”也是如此。https://github.com/firebase/quickstart-ios/issues/5 (3认同)
  • 拯救我的一天很好的答案 (2认同)
  • 这是一个非常好的解决方案,应该被接受为答案。 (2认同)
  • @smileBot 你可以跳过 `-r`,更多信息:[Linux/Unix 中的 cp 命令](https://www.rapidtables.com/code/linux/cp.html) (2认同)
  • `“调试”中的“${CONFIGURATION}”) cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Staging-Info.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;; "发布" ) cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;; *) cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Staging-Info.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;; esac` 我这样做了,但它总是在两种模式(调试和发布)下使用 GoogleService-Staging-Info.plist。这里有什么问题吗?? (2认同)

Ess*_*sry 60

@inidona的回答对我有用.我把它转换成Swift之后

对于Swift 2.3:

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

对于Swift 3.0:

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

对于Swift 4.0:

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

  • 最近的文件称“警告:这种方法在某些情况下可能会影响分析收集” https://firebase.google.com/docs/projects/multiprojects (3认同)
  • 使用上面的代码,您是否在不同位置有两个不同的文件“GoogleService-Info.plist”文件,或者可能有两个具有不同名称的文件。您能否提供更多关于实际文件名是什么以及它们放置在哪里的信息? (2认同)
  • 给我'无法找到配置文件:'GoogleService-Info.plist'' (2认同)

Bru*_*mos 24

查看这篇文章:https://medium.com/@brunolemos/how-to-setup-a-different-firebase-project-for-debug-and-release-environments-157b40512164

在Xcode上,在项目中创建两个目录:DebugRelease.把每个GoogleService-Info.plist文件放在那里.

在方法AppDelegate.m内部didFinishLaunchingWithOptions,输入代码:

Objective-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];
Run Code Online (Sandbox Code Playgroud)

斯威夫特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)
Run Code Online (Sandbox Code Playgroud)

将两个文件夹DebugRelease文件夹拖放到Build Phases > Copy Bundle Resources:

构建阶段>复制捆绑资源

而已 :)

  • 这对我有用。你必须在那里添加这些文件夹作为参考,否则它确实会崩溃。谢谢! (2认同)

小智 23

我认为您可以使用这种方式动态配置您的GoogleService-Info.plist,并为不同的捆绑标识符使用不同的名称.

ciao Andreas

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
[FIRApp configureWithOptions:options];
Run Code Online (Sandbox Code Playgroud)

  • 使用上面的代码,您在不同位置有两个不同的文件GoogleService-Info.plist文件,还是两个名称不同的文件.您能否提供一些有关实际文件名及其放置位置的更多信息? (5认同)
  • 我在configureWithOptions调用期间在日志中遇到此错误:`找不到配置文件:'GoogleService-Info.plist'` (3认同)

Bjø*_*gil 16

这个答案很大程度上受到@abbood答案的启发,但更具体地说明了如何去做。

对于您的每个目标,例如 dev、stg、prod:

  • 下载对应的GoogleService-Info.plist以您的目标命名的单独文件夹
  • 在 Xcode 中,右键单击您的应用程序文件夹并选择 Add files to "your app" 在此处输入图片说明
  • 选择包含目标的文件夹GoogleService-Info.plist,确定Copy items if neededCreate groups被选中,在目标列表中只勾选相应的目标,然后按Add 在此处输入图片说明

就是这样。现在你应该有类似这个结构的东西

在此处输入图片说明

当您构建目标时,GoogleService-Info.plist将使用正确的。

  • 实际上,这些是针对不同的构建目标的。问题是如何处理模式而不是目标。但这似乎是理想的选择 (3认同)
  • 我已经尝试这样做好几天了,而且效果完美。只需确保删除对“GoogleServices-Info.plist”的任何其他引用,否则您可能会收到:“错误:多个命令生成 GoogleServices-Info.plist...” (2认同)

Mas*_*aza 15

迟到了,但我想我必须发布这个答案来帮助新开发人员,我找到了一篇很好的文章来解决我的问题,我保证它也可以帮助你:)
检查这篇文章也可以解决你的问题。

第一步:
将你的Firebase开发环境对应的GoogleService-Info.plist复制到Dev目录下。同理,将你的Firebase生产环境对应的GoogleService-Info.plist复制到Prod目录下。确保取消选中“需要时复制项目”“添加到目标”下的所有目标。

(第 1 步图片链接(由于声誉较低,我无法添加图片))

第 2 步:
在 Xcode 项目导航器中,选择应用程序目标。切换到顶部的 Build Phases 选项卡,然后添加一个New Run Script Phase。将阶段命名为“Setup Firebase Environment GoogleService-Info.plist”或类似名称,并将其放在“Copy Bundle Resources”步骤之前。

第 3 步:
实现一个 shell 脚本,该脚本将根据构建配置将适当的GoogleService-Info.plist复制到应用程序包中。将以下 shell 脚本复制并粘贴到您刚刚创建的运行脚本阶段:

# 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
Run Code Online (Sandbox Code Playgroud)


Var*_*rry 15

我发现,对于单个目标,唯一 100% 可行的方法是在构建期间复制与构建配置相对应的 plist;但这里的这些答案在如何做到这一点的细节上有所不同,而且没有人对我来说足够方便。我的回答基于@KnightFighter 的回答和Medium 上的这篇文章。


首先将所有不同的plist添加到具有不同名称的项目中(它们不能作为资源添加到目标中):

在此输入图像描述

接下来创建用户定义的构建设置,您可以在其中将特定的 plist 分配给每个构建配置:

在此输入图像描述

最后添加“运行脚本”阶段的代码:

GOOGLE_SERVICE_INFO_PLIST_SOURCE=${PROJECT_DIR}/${TARGET_NAME}/${GOOGLE_SERVICE_INFO_PLIST_FILENAME}

if [ ! -f $GOOGLE_SERVICE_INFO_PLIST_SOURCE ]
then
    echo "${GOOGLE_SERVICE_INFO_PLIST_SOURCE} not found."
    exit 1
fi

GOOGLE_SERVICE_INFO_PLIST_DESTINATION="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"

cp "${GOOGLE_SERVICE_INFO_PLIST_SOURCE}" "${GOOGLE_SERVICE_INFO_PLIST_DESTINATION}"
Run Code Online (Sandbox Code Playgroud)

我认为这种方式有一些优点:

  • 不需要有文件夹层次结构来存储 plist;
  • 如果单个 plist 用于多个配置,则无需复制文件;
  • 如果您需要添加配置或重新分配 plist,则在构建设置中更改文件名比编辑脚本更容易;特别是对于非程序员(即构建经理)。


abb*_*ood 10

我注意到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
Run Code Online (Sandbox Code Playgroud)

关键是这个

从与您的应用目标捆绑在一起的文件GoogleServices-Info.plist中读取

因此,我只是复制了相同的文件并将其放置在不同的目录中,并将其绑定到不同的目标:

在此处输入图片说明


Ona*_*ato 6

如果GoogleService-Info.plist名称不同,则会影响您的分析结果。Firebase会就此警告您。https://github.com/firebase/firebase-ios-sdk/issues/230#issuecomment-327138180。因此,这些运行时解决方案都无法提供最佳的分析结果。

有两种解决方案不会与Analytics混淆。

  1. 对每个方案使用不同的目标,并将每个版本GoogleService-Info.plist与自己的目标相关联。请参阅Xcode右侧文件检查器中的“ 目标成员身份”。有关更多信息,请参见此问题

  2. 使用构建阶段脚本到正确的版本复制GoogleService-Info.plist到构建目录。我将不同的捆绑软件ID用于暂存和生产。这使我可以并行安装两个版本的应用程序。这也意味着在下面的脚本中,我可以GoogleService-Info.plist使用包ID 命名不同的文件。例如:

    • 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"
Run Code Online (Sandbox Code Playgroud)

注意:您将不得不更改PATH_TO_CONFIG以适合您的设置。

构建阶段脚本

  • 这是迄今为止最好的解决方案。因为 Firebase Crashlytics 只能使用 GoogleService-Info.plist 文件通过“upload-symbols”脚本上传 dSYM 文件 - 此解决方案完美运行! (2认同)

pie*_*e23 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)
}
Run Code Online (Sandbox Code Playgroud)


Ara*_*ell 6

我通过这个解决了这个问题:

    #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
Run Code Online (Sandbox Code Playgroud)


Sag*_*tel 6

因此,我思考了同样的问题,并使用了之前帖子中的一些想法,其中一些帖子针对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}'."
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在您选择的配置文件夹(上例中的“Firebase”)中,每个配置的嵌套文件夹与其各自的配置完全相同(区分大小写),其中放置各自的GoogleServices-Info.plist文件,如下所示:

在此输入图像描述

最后但并非最不重要的一点是,我还想确保根级别GoogleServices-Info.plist不会意外添加到项目中,因此我将以下内容添加到我的 .gitignore 中。

# Ignore project level GoogleService-Info.plist
/[Project Name]/GoogleService-Info.plist
Run Code Online (Sandbox Code Playgroud)


Bor*_*zin 6

假设我们有两个配置集,developproduction。你必须做两件事:

  1. 重命名两个 plist 以符合给定的配置:
  • GoogleService-Info-develop.plist
  • GoogleService-Info-production.plist
  1. 添加一个运行脚本,为所选配置复制正确的 plist:
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"
Run Code Online (Sandbox Code Playgroud)

运行脚本需要定位在FirebaseCrashlytics脚本之前。

您可以像以前一样为单个方案初始化 firebase: FirebaseApp.configure()


Kyl*_*enn 6

这是我的 @Essam 解决方案版本。

  1. Google-Services.plist使用默认标识符为默认方案 ( ) 生成 GoogleServices 版本
  2. 为变体方案 ( Google-Services-debug.plist) 生成具有正确标识符的第二个 GoogleServices 版本
  3. 将两者添加到项目的根目录(在其指南中告诉您的位置)

在您要添加配置的位置添加此代码:

        let bundleID = Bundle.main.bundleIdentifier
        if (bundleID!.contains("debug")) {
            let resource: String = "GoogleService-Info-debug"
            let filePath = Bundle.main.path(forResource: resource, ofType: "plist")!
            let options = FirebaseOptions(contentsOfFile: filePath)
            FirebaseApp.configure(options: options!)
        } else {
            FirebaseApp.configure()
        }
Run Code Online (Sandbox Code Playgroud)


小智 3

我认为如果不使用它是不可能实现的,GoogleService-Info.plist.因为在开始将 iOS 应用程序与 Google Sign-In 组件集成之前,您必须下载依赖项并配置 Xcode 项目。这个过程表明,GoogleService-Info.plist其中有很大的因素。

因此,这个问题中的解决方案和想法可以帮助您解决问题。只需将应用程序的主副本GoogleService-Info plist移至 2 个单独的文件夹中,然后在每个目标上使用构建阶段“复制文件”将目标特定 plist 导入到 Resources 文件夹中。

另请检查这个问题,它可能会为您的问题提供更多信息/想法。