具有多个目标的iOS扩展

具有多个目标的iOS扩展,ios,plist,code-signing,ios-app-extension,bundle-identifier,Ios,Plist,Code Signing,Ios App Extension,Bundle Identifier,在iOS 8中,当我们创建应用程序扩展时,我们必须决定它连接到哪个目标。扩展将具有与目标相同的bundle ID前缀 之后有没有办法改变目标 如果我的项目包含2个(或更多)目标(例如一个用于调试/模拟器,一个用于生产/设备),那么使用扩展的最佳方式是什么?我是否需要创建另一个扩展并复制代码(为两个目标保留相同的代码非常麻烦) 您需要为每个ID创建多个扩展,但您可以创建动态框架并将其与每个扩展链接起来。这样您就不需要复制代码了。看起来您应该能够用自己的Info.plist复制扩展目标,而不是其他任

在iOS 8中,当我们创建应用程序扩展时,我们必须决定它连接到哪个目标。扩展将具有与目标相同的bundle ID前缀

  • 之后有没有办法改变目标
  • 如果我的项目包含2个(或更多)目标(例如一个用于调试/模拟器,一个用于生产/设备),那么使用扩展的最佳方式是什么?我是否需要创建另一个扩展并复制代码(为两个目标保留相同的代码非常麻烦)

  • 您需要为每个ID创建多个扩展,但您可以创建动态框架并将其与每个扩展链接起来。这样您就不需要复制代码了。

    看起来您应该能够用自己的Info.plist复制扩展目标,而不是其他任何东西

    但是,当您创建扩展时,Xcode会将“嵌入应用程序扩展”添加到应用程序目标的构建阶段,如下所示,目前还没有用户界面可以做到这一点

    仍然可以为第二个目标创建扩展名,然后删除除.plist之外的所有文件,并修复需要修复的内容。以下是一个逐步的步骤:

    • 为“目标1”创建“扩展1”
    • 为“目标2”创建“扩展2”
    • 删除为“扩展名2”创建的所有文件,但其Info.plist除外
    • 使“扩展2”的“构建阶段”目标与“扩展1”的构建阶段相同。通常,这是将必要的.m文件添加到“编译源代码”阶段,将资源添加到“复制捆绑资源”阶段

    要与其他目标共享一个小部件,您只需添加widget.appex target 为
    常规
    配置选项卡中的每个父目标执行
    嵌入式二进制文件

    然后,您将在
    构建阶段自动获得
    嵌入应用程序扩展
    区域


    我已经创建了一个运行脚本来支持此要求

    #!/bin/sh
    buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${SRCROOT}/ImagePush/Info.plist"
    
    buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFOPLIST_FILE")
    /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildVersion" "${SRCROOT}/ImagePush/Info.plist"
    
    buildID=${PRODUCT_BUNDLE_IDENTIFIER}
    /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $buildID.ImagePush" "${SRCROOT}/ImagePush/Info.plist"
    
    这是我的分机


    将您需要的添加到目标并添加确保在构建阶段扩展设置之前运行此脚本,然后只需执行两次构建操作(PS:第一次失败,将尝试改进),它将支持多个目标这是我的设置:我有3个目标(生产、暂存、本地)还有一个扩展目标,我不想重复3次

    为了澄清客户的答案,请编辑每个家长目标的计划:

    生成>预操作>新建运行脚本操作>从(父方案)提供生成设置

    为每个扩展粘贴以下内容:

    #!/bin/bash
    
    buildID=${PRODUCT_BUNDLE_IDENTIFIER}
    extId="notification-service"
    
    /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $buildID.$extId" "${SRCROOT}/${extId}/Info.plist"
    

    在我的项目中,我需要构建一些不同版本的应用程序(细节不同,例如每个应用程序都有不同的徽标)

    假设有大约10个“应用程序”目标,我无法想象为每个主要目标添加通知内容和通知服务扩展(在这种情况下,我将总共维护30个目标-疯狂)

    我在“嵌入应用程序扩展”阶段后运行脚本()
    这将覆盖应用程序扩展plists和授权、应用程序版本中的捆绑包id,更改配置文件并重新签名捆绑包。

    xconfigs是基于Xcode方案更改修改plist条目和代码中变量的好方法

    如果您希望更改基于方案的给定扩展的
    捆绑标识:

  • 为扩展名创建一个Xcconfig文件。我的
    iMessageExtension Debug.xcconfig
    有以下条目:
    PRODUCT\u BUNDLE\u IDENTIFIER=$(APP\u BUNDLE\u IDENTIFIER)。iMessageExtension

  • 在Xcode文件检查器中,单击项目>在详细信息窗格中,单击项目>信息选项卡>添加配置

  • 我创建了一个调试配置

  • 在新创建的配置文件中,钻取扩展名>选择配置文件

  • 创建新方案:在新方案的“运行”选项卡中,可以选择新创建的配置。对于额外发布,也可以执行相同的过程

  • 我们创建的Xcconfig选项可以直接在iMessageExtension>Info.plist中使用:
    Bundle标识符:$(产品\u Bundle\u标识符)

  • 如果需要在基于xcconfig变量的代码中引用变量:

    例如,我想根据选择的Xcode方案更改我的应用程序初始屏幕:

    Xcconfig:
    INITIAL_SCREEN=tabBarHome

    Plist:
    initialScreen:$(初始屏幕)

    Swift代码:
    var initialScreen=object(forInfoDictionaryKey:“initialScreen”)作为?字符串

    编辑 2种解决方案:

    • 使用
      xconfig
      。见这里提到的答案:和。还可以在此SO问题上搜索
      XCConfig
      。你可能会找到一些评论
    • 通过脚本改变一切。我的答案是这样做
    老实说,我认为
    XCConfig
    解决方案要优雅得多。你只是把东西换进换出,而不是试图以一个非常特定的顺序覆盖所有东西


    其他每一个答案都有一部分是必要的。经过一些重要的修改,我能够把事情做好

    你需要做三件事:

    • 更改appex的bundleId(应用程序扩展)
    • appex捆绑包更改后重新签名。虽然应用程序在模拟器上正确运行,但如果没有此步骤,它将无法在真实设备上运行
    • 设置适当的配置文件。(排除了这个答案,因为我还不知道怎么做)
    注意:在附录嵌入之前,您不能签署附录。因此,“重新签署appex”步骤需要在“嵌入应用程序扩展”步骤之后进行。类似地,如果bundleId没有以父应用程序的bundleId作为前缀,则不能嵌入appex

    最后的订单应该是
    -replace keypath -type value 
    
    plutil -replace \
    CFBundleIdentifier -string \
    $PRODUCT_BUNDLE_IDENTIFIER.contentExt \
    "$BUILT_PRODUCTS_DIR/contentExt.appex/Info.plist"
    
    /usr/bin/codesign \
    --force \
    --sign $EXPANDED_CODE_SIGN_IDENTITY \
    --entitlements $CONFIGURATION_TEMP_DIR/ContentExtension.build/ContentExtension.appex.xcent \
    --timestamp=none \
    "$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/ContentExtension.appex"