之前文章 以无线方式安装企业内部应用
将企业内部专有 App 分发到 Apple 设备
Apple 设备支持以无线方式安装企业内部专有 App,无需使用 Mac 或通过 App Store。您必须有预置描述文件才能分发此类 App。您可以使用移动设备管理 (MDM) 解决方案安装和管理预置描述文件,然后用户通过 MDM 或 App 更新进行下载并安装。预置描述文件过期之前,请参阅 Apple 开发者网站为 App 创建新描述文件。对于 iOS 或 iPadOS App,请使用新预置描述文件为首次安装该 App 的用户导出新的 App 捆绑包(.ipa 文件)。
您可以通过两种方式分发企业内部专有 App:
-
使用 MDM
-
使用网站
这两种方法都需要为分发准备 App,包括准备清单。
未被监督的设备所需的 App
在 iOS 15 或更高版本和 iPadOS 15 或更高版本中,MDM 管理员可于注册过程中在未被监督的设备上安装 App。用户注册 MDM 解决方案时必须同意此安装。若要启用此功能,管理员需在 MDM 描述文件的 RequiredAppIDForMDM 属性中设定该 App Store App 的 iTunesStoreID。然后管理员必须确保 App 已有设备许可或用户许可,并在进行 MDM 注册后发送 InstallApplication
命令。MDM 管理员还可添加被管理 App 的属性以确保用户无法移除该 App。如果用户已安装了该 App,会收到请求对 App 进行 MDM 管理的提醒。有关 MDM 有效负载最新更改的更多信息,请参阅 Apple 开发者网站上的 MDM 注册页面。
为无线分发准备企业内部专有 App
为准备企业内部专有 App 以进行无线分发,请构建归档版本(.ipa 文件)和用于启用无线分发和 App 安装的清单文件。使用 Xcode 创建版本化的 App 归档,然后将 App 导出以用于分发到组织。Xcode 使用分发证书并包括合适的预置描述文件。清单文件是一个 XML 属性列表(.plist 文件),可供 Apple 设备用来从您的网页服务器上查找、下载和安装 App。清单文件由 Xcode 创建,使用的是您在共享用于分发到组织的归档 App 时所提供的信息。若要查看属性和关联值列表,请参阅 Apple 开发者网站上的安装应用程序命令。
适用于 Mac 电脑的受管理的企业内部专有 App
虽然所有批量购买的 App 和“自定 App”都可作为受管理的 App 安装,但只有部分企业内部专有 App 可被管理。若要变为可被管理,App 软件包必须:
-
不包含任何嵌套软件包
-
只包含单个 App
-
安装在“/应用程序”中
受管理的 App 必须保留在“/应用程序”文件夹中才视为被管理。
使用 MDM 来分发 App
若要使用 MDM,请通过 InstallApplication
命令来使用清单文件。有关更多信息,请参阅针对 Apple 设备的 MDM 命令。
使用网站来分发 App
若要通过无线方式安装 App,iOS 和 iPadOS App 必须满足以下要求:
-
App 的格式必须为 .ipa,并且使用企业内部预置描述文件进行构建。
-
必须有 XML 清单文件。
-
必须从地址以 HTTPS 开头的网站下载。
-
必须由设备上信任的证书签名。
-
网络配置必须允许设备访问 Apple 服务器。有关更多信息,请参阅 Apple 支持文章:在企业网络上使用 Apple 产品。
为了安装软件包,用户需要使用特殊的 URL 前缀从您的网站上下载清单文件。您可以通过 iMessage 信息或邮件来分发用于下载清单文件的 URL。以下是添加了前缀的示例链接:
<a href="itms-services://?action=download-manifest&url=https://example.com/manifest.plist">Install App</a>
您负责设计和托管用于分发这些类型 App 的网站。请确保用户已通过认证,且网站可通过内网或互联网访问(取决于您的需求)。您的网站可以是链接到清单文件的单个页面。当用户轻点网站链接时,会下载清单文件,并触发下载和安装网页所描述的内容。
请确保遵循以下额外指南:
-
请勿添加直接指向归档 App (.ipa) 的网站链接。载入清单文件时,设备会下载该 .ipa 文件。虽然 URL 的协议部分是“itms-services”,但 App Store 并不参与此过程。
-
请确保 .ipa 文件可通过 HTTPS 访问,并且您的站点已使用 iOS 和 iPadOS 信任的证书进行了签名。如果自签名证书没有受信任的锚点并且无法由设备验证,安装会失败。
将这些项目上传到网站上可供已认证的用户访问的区域:
-
清单文件(文件扩展名为 .plist)
-
App 文件(文件扩展名为 .ipa)
您可能需要配置网页服务器,让清单文件和 App 文件可正确传输。对于服务器,请将 MIME 类型添加到网页服务的 MIME 类型设置:
-
application/octet-stream ipa
-
text/xml plist
对于微软的互联网信息服务器 (IIS),请使用 IIS Manager 在服务器的“属性”页面中添加 MIME 类型:
-
.ipa application/octet-stream
-
.plist text/xml
【注】创建自助服务门户时,请考虑在用户的主屏幕中添加一个 Web Clip,以便用户轻松返回门户以获取以后需要的信息,如新的配置描述文件、推荐的 App Store App 以及允许用户在 MDM 解决方案中进行注册。
证书验证
用户首次打开 App 时,系统会通过联系 Apple OCSP 服务器来验证分发证书。如果证书已撤销,App 将不会启动。为了验证状态,设备必须能够访问 ocsp.apple.com。
OCSP 响应会在设备上缓存一段时间(由 OCSP 服务器指定),当前为 3 到 7 天之间。在重新启动设备和缓存的响应过期之前,将不会再次检查证书的有效性。如果当时收到撤销命令,系统将阻止 App 运行。
【警告】撤销分发证书会导致使用该证书签名的所有 App 失效。只有万不得已时才应撤销证书,比如确定专用密钥已丢失或确信证书已遭破解。
提供更新的企业内部专有 App
您自己分发的 App 不会自动更新。有新版本时,应通知用户进行更新并指导他们安装 App。请考虑让 App 检查更新,并在打开 App 时通知用户。请确保通知中提供了 itms-services 链接。您还可以使用 App 内部的 openURL 来安装更新。
如果想要用户保留他们设备上储存的 App 数据,请确保新版本与要替换的版本使用的捆绑标识符相同,并告知用户在安装新版本之前不要删除旧版本。
预置描述文件过期之前,请通过 iOS 开发者网站或 iPadOS 开发者网站为 App 创建新描述文件。对于首次安装 App 的用户,请使用新的预置描述文件导出新的 App 捆绑包(.ipa 文件)。
如果用户已有该 App,您不妨设定发布下一个版本的时间,并在该版本中包括新预置描述文件。这样用户在使用 App 工作时不会被打断。如果不想这样做,您可以仅分发新的 .mobileprovision 文件,这样用户便不必再次安装该 App。新的预置描述文件会覆盖 App 归档中已有的描述文件。
分发预置描述文件自签发之日起 12 个月后过期。过期后,系统会删除描述文件,App 将不会启动。
如果您的分发证书过期,App 将不会启动,而您需要使用新的分发证书来重新构建 App。分发证书自签发之日起 3 年内有效,或者在您的 Apple Developer Enterprise Program(Apple 开发者企业级计划)成员资格过期之前一直有效,以二者中更早时间为准。若要防止证书过期,请确保在成员资格过期之前先进行续订。
您可以拥有同时处于活跃状态的两个证书,并且它们彼此独立。第二个证书提供了一个重叠期,让您能够在第一个证书过期前更新 App。请求第二个分发证书时,请确保不要撤销第一个证书。
无线 App 分发故障诊断
如果无线 App 分发失败,并显示“无法下载”信息:
-
请确定 App 已正确进行签名。测试方法是使用 Apple Configurator 将它安装到设备上,然后查看是否发生错误。
-
请确定清单文件的链接是否正确,清单文件是否可供网络用户访问。
-
请确保清单文件中 .ipa 文件的 URL 正确,并且网络用户可通过 HTTPS 访问该 .ipa 文件。
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- array of downloads. -->
<key>items</key>
<array>
<dict>
<!-- an array of assets to download -->
<key>assets</key>
<array>
<!-- software-package: the ipa to install. -->
<dict>
<!-- required. the asset kind. -->
<key>kind</key>
<string>software-package</string>
<!-- optional. md5 every n bytes. will restart a chunk if md5 fails. -->
<key>md5-size</key>
<integer>10485760</integer>
<!-- optional. array of md5 hashes for each "md5-size" sized chunk. -->
<key>md5s</key>
<array>
<string>41fa64bb7a7cae5a46bfb45821ac8bba</string>
<string>51fa64bb7a7cae5a46bfb45821ac8bba</string>
</array>
<!-- required. the URL of the file to download. -->
<key>url</key>
<string>https://www.example.com/apps/foo.ipa</string>
</dict>
<!-- display-image: the icon to display during download.-->
<dict>
<key>kind</key>
<string>display-image</string>
<!-- optional. indicates if icon needs shine effect applied. -->
<key>needs-shine</key>
<true/>
<key>url</key>
<string>https://www.example.com/image.57x57.png</string>
</dict>
<!-- full-size-image: the large 512x512 icon used by iTunes. -->
<dict>
<key>kind</key>
<string>full-size-image</string>
<!-- optional. one md5 hash for the entire file. -->
<key>md5</key>
<string>61fa64bb7a7cae5a46bfb45821ac8bba</string>
<key>needs-shine</key>
<true/>
<key>url</key><string>https://www.example.com/image.512x512.jpg</string>
</dict>
</array>
<key>metadata</key>
<dict>
<!-- required -->
<key>bundle-identifier</key>
<string>com.example.fooapp</string>
<!-- optional (software only) -->
<key>bundle-version</key>
<string>1.0</string>
<!-- required. the download kind. -->
<key>kind</key>
<string>software</string>
<!-- optional. displayed during download; typically company name -->
<key>subtitle</key>
<string>Apple</string>
<!-- required. the title to display during the download. -->
<key>title</key>
<string>Example Corporate App</string>
</dict>
</dict>
</array>
</dict>
</plist>
网友评论