53

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

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

8 回答 8

35

要与其他目标共享一个小部件,您只需为配置选项卡Embedded Binaries中的每个父目标添加 widget.appex 目标General

在此处输入图像描述

然后你会自动得到Embed App Extensions面积Build Phases

在此处输入图像描述

于 2016-03-23T18:53:25.060 回答
25

这是我的设置:我有 3 个目标(生产、暂存、本地)和一个我不想重复 3 次的扩展目标。

只是为了澄清Neo Chen的答案,编辑每个父目标的方案:

Build > Pre-actions > New Run Script Action > 从(父方案)提供构建设置。

为每个扩展粘贴这个:

#!/bin/bash

buildID=${PRODUCT_BUNDLE_IDENTIFIER}
extId="notification-service"

/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $buildID.$extId" "${SRCROOT}/${extId}/Info.plist"

似乎在第一次构建时工作。

于 2018-06-28T02:03:14.317 回答
13

似乎您应该能够仅使用其自己的 Info.plist 复制 Extension 目标,但不能复制其他任何内容。

但是,当您创建扩展时,Xcode 会将“嵌入应用扩展”添加到应用目标的构建阶段,如下所示,并且还没有 UI 可以执行此操作。

在此处输入图像描述

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

  • 为“目标 1”创建“扩展 1”
  • 为“目标 2”创建“扩展 2”
  • 删除为“扩展 2”创建的所有文件,除了 Info.plist
  • 使“扩展 2”目标的“构建阶段”与“扩展 1”的构建阶段相同。通常是将必要的 .m 文件添加到“编译源”阶段,并将资源添加到“复制捆绑资源”阶段
于 2014-10-11T01:05:18.717 回答
7

我创建了一个运行脚本来支持这个要求

#!/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"

ImagePush 是我的扩展

添加到您需要的目标并添加确保此脚本在构建阶段中的扩展设置之前运行,然后您只需要执行两次构建操作(PS:第一次它会失败,将尝试改进)它会支持多目标

于 2017-10-13T03:43:11.493 回答
5

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

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

我在“嵌入应用程序扩展”阶段之后运行一个脚本(https://gist.github.com/damian-rzeszot/0b23ad87e5ab5d52aa15c095cbf43c59),它覆盖应用程序扩展列表和权利、应用程序版本中的捆绑ID,更改配置文件并重新签署捆绑。

于 2020-04-20T00:00:57.863 回答
4

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

如果您想Bundle identifier根据方案更改给定扩展的示例:

  1. 为您的扩展创建一个 Xcconfig 文件。我iMessageExtension-Debug.xcconfig有这个条目: PRODUCT_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).iMessageExtension

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

  3. 我创建了一个调试配置。

  4. 在您新创建的扩展中钻取配置 > 选择配置文件

  5. 创建一个新方案:在该新方案的运行选项卡中,您可以选择新创建的配置。可以为额外发布执行相同的过程。

  6. 我们创建的 Xcconfig 选项可以直接在 iMessageExtension > Info.plist 中使用: Bundle identifier : $(PRODUCT_BUNDLE_IDENTIFIER)

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

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

配置: INITIAL_SCREEN = tabBarHome

列表: initialScreen : $(INITIAL_SCREEN)

SWIFT代码: var initialScreen = object(forInfoDictionaryKey: "initialScreen") as? String

于 2020-08-25T17:06:52.670 回答
3

编辑

2个解决方案:

  • 使用XCConfig. 请参阅此处提到的答案:https ://stackoverflow.com/a/63583849/5175709和此处。也搜索XCConfig这个 SO question。你可能会发现一些评论。
  • 通过脚本改变一切。我的回答是这样做。

老实说,我认为XCConfig解决方案要优雅得多。你只是交换东西,而不是试图以非常特定的顺序覆盖所有东西......


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

你需要做三件事:

  • 更改 appex 的 bundleId(应用程序扩展)
  • 更改捆绑包后重新签署appex。虽然应用程序在模拟器上正确运行,但如果没有这一步,它将无法在真实设备上运行。
  • 设置适当的配置文件。(从这个答案中排除,因为我还不知道该怎么做)

注意:您无法在 appex 嵌入之前对其进行签名。因此,“重新签署 appex”步骤需要在“嵌入应用程序扩展”步骤之后进行。同样,如果 bundleId 没有以父应用程序的 bundleId 为前缀,则无法嵌入 appex。

最终订单应如下所示:

在此处输入图像描述

更改 appex 的 bundleId

plutil的 sytanx 是这样的:

-replace keypath -type value 

所以就这样做:

plutil -replace \
CFBundleIdentifier -string \
$PRODUCT_BUNDLE_IDENTIFIER.contentExt \
"$BUILT_PRODUCTS_DIR/contentExt.appex/Info.plist"

如果您想了解更多信息plutil(请参阅此处此处了解更多信息)。PlistBuddy有点老了。

注意: ContentExtension 是我拥有的目标名称。确保你正确使用你的

重新签署appex

/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"

注意: ContentExtension 是我拥有的目标名称。确保你正确使用你的

最终结果是这样的:

在此处输入图像描述

不要忘记为每个目标重复这些步骤。确保正确的最佳方法是将 appex 的 bundleId 设置为完全错误的值,然后在真实设备上测试所有目标。如果您在 sim 上对其进行测试,那么您将无法验证代码签名是否正常工作。

FWIW 通常最好将所有 shell 转储到一个目录中,然后从那里引用它们。但是为了这篇文章的简单起见,我没有这样做。

还要确保你看到原来的要点,如果你用它来改变你所有的 appexes,它会更聪明。您只需要传递应用程序的名称,然后它就会找出其余的...

于 2020-12-08T21:43:09.650 回答
1

您需要为每个 ID 创建多个扩展,但您可以创建动态框架并将其与每个扩展链接。然后你就不需要复制你的代码了。

于 2014-09-26T14:41:39.117 回答