通过Mac App Store分发应用之签名过程

背景

最近接到需要编写一个Unity版本的SDK供游戏工程师使用,并上架应用到Mac App Store。之前从未有过Unity开发和Mac App上架的经验,所以写文章记录自己整个开发过程,以备需要时查看。

我们都知道在Mac OS上安装的应用,有两个下载渠道:

  • 官方渠道:Mac App Store
  • 非官方渠道:公司官网等非Mac App Store来源

我们本身也有在iOS App Store上架的应用,根据苹果官方文档的描述,我们可以直接将iOS 应用平滑迁移到Mac上,仅仅只需要在【App Store Connect - App - 价格与销售范围】上勾选 "提供此App 至 mac os"上,见下图:

但我们希望能够获得Mac App Store的官方流量和推荐,所以选择为当前应用增加mac os平台,发布完全适配Mac平台的新应用。于是,就有了Unity接入Mac内购和Mac签名的开发过程。

这篇文章主要讲述了我帮助游戏客户端进行Mac App的代码和安装包签名,以及对苹果相关官方文档的学习,希望可以帮助到大家。

1、签名过程

注意:如果使用Xcode直接上传到Mac App Store则不用签名和公证。

1.1、使用unity编译后修改info.plist文件

1)App Uses Non-Exempt Encryption :设置为 NO,这样在Apple Connect Strore - App - 构建版本处,就不需要每次都确认"出口合规证明";

vbnet 复制代码
  <key>ITSAppUsesNonExemptEncryption</key>
  <false/>

2)检查 Bundle OS Type code 的值:其value值是一个四字母的代码,用于指示包类型。对于应用程序,代码是APPL;对于框架,是FMWK;对于捆绑包,则是BNDL。默认值是从捆绑扩展名中推导出来的,如果无法推导,则默认值是BNDL。

vbnet 复制代码
  <key>CFBundlePackageType</key>
  <string>APPL</string>

3)App Category(LSApplicationCategoryType) :设置应用程序的类型

vbnet 复制代码
  <key>LSApplicationCategoryType</key>
  <string>public.app-category.games</string>

4)LSMinimumSystemVersion:设置App在 macOS 中运行所需的最低操作系统版本。

vbnet 复制代码
  <key>LSMinimumSystemVersion</key>
  <string>13.0.0</string>

1.2、创建并修改.entitlements文件

使用Xcode创建一个和你项目同名的Mac工程,不需要配置该项目的描述文件和证书,仅仅只需要添加App Sandbox Capability。

我们项目是一个游戏项目,所以按照项目功能,勾选了网络和文件读写。

打开生成的App.entitlements,添加TeamID和AppID

vbnet 复制代码
  <key>com.apple.developer.team-identifier</key>
  <string>TeamID</string>
  <key>com.apple.application-identifier</key>
  <string>AppID</string>

补充:上传到Mac App Store应用都必须开启沙盒功能,验证签名后的app是否开启沙盒功能,苹果提供了两种方式

1)活动监视器查看

2)命令行查看

css 复制代码
% codesign -dvvv --entitlements - <path to your app>

1.3、在.app/Contents路径下添加发布环境的.provisionprofile文件

注意: 必须.app/Contents路径下,文件名也必须是embedded.provisionprofile

从Mac App Store 或 TestFlight下载后的应用,.app/Contents就不会显示embedded.provisionprofile文件了。

1.4、签名指令

ruby 复制代码
# 1. 对~/XXX.app/Contents/PlugIns路径下的bundle进行代码签名,注意不可以使用--entitlements选项,注意这里使用的是:3rd Party Mac Developer Application证书
# codesign -f -s <CertificationName> <BundlePath>
$ codesign -f -s '3rd Party Mac Developer Application: AAA' "XXX.app/Contents/PlugIns/unitypurchasing.bundle"
# 终端会打印:XXX.app/Contents/PlugIns/unitypurchasing.bundle: replacing existing signature
​
# 2. 对~/XXX.app/Contents/Frameworks路径下的库文件进行代码签名,注意不可以使用--entitlements选项,注意这里使用的是:3rd Party Mac Developer Application证书
# codesign -f -s <CertificationName> <FrameworkPath>
$ codesign -f -s '3rd Party Mac Developer Application: AAA' "XXX.app/Contents/Frameworks/libmonobdwgc-2.0.dylib"
# 终端会打印:XXX.app/Contents/Frameworks/libmonobdwgc-2.0.dylib: replacing existing signature
​
# 3. 对.app进行代码签名,注意这里使用的是:3rd Party Mac Developer Application证书
# codesign -f -s <CertificationName> --entitlements <EntitlementsPath> <AppPath>
$ codesign -f -s '3rd Party Mac Developer Application: AAA' --entitlements "/Users/XXX/Desktop/App.entitlements" "/Users/XXX/Desktop/XXX.app"
# 终端会打印:XXX.app: replacing existing signature
​
# 4. 生成安装包并进行安装包签名,注意这里使用的是:3rd Party Mac Developer Installer证书
# productbuild --component <AppPath> /Applications --sign <CertificationName> <PkgPath>
$ productbuild --component /Users/XXX/Desktop/XXX.app /Applications --sign "3rd Party Mac Developer Installer: AAA" /Users/XXX/Desktop/XXX.pkg
​
# 终端会打印:
productbuild: Adding component at /Users/XXX/Desktop/XXX.app
productbuild: Signing product with identity "3rd Party Mac Developer Installer: AAA" from keychain /Users/XXX/Library/Keychains/login.keychain-db
productbuild: Adding certificate "Apple Worldwide Developer Relations Certification Authority"
productbuild: Adding certificate "Apple Root CA"
productbuild: Wrote product to /Users/XXX/Desktop/XXX.pkg
productbuild: Supported OS versions: [Min: 13.0.0, Before: None]

补充: 是在 "钥匙串访问" 中复制粘贴的证书名称

2、 签名过程遇到的问题

1、Asset validation failed (90869) Invalid bundle. The "NTSDK.app" bundle supports arm64 but not Intel-based Mac computers. Your build must include the x86_64 architecture to support Intel-based Mac computers. To support arm64 only, your macOS deployment target must be 12.0 or higher. For details, view: developer.apple.com/documentati.... (ID: 3d0f10fb-1a41-4d45-8b40-d1227cdd3f4b)

原因: Apple要求如果应用只支持Apple Silicn,macOS deployment target必须 >=12.0,而我们Unity Build的Mac app设置是10.13.0。

解决: 修改Info.plist文件中, LSMinimumSystemVersion 对应的value值,按照需求设置,只要大于12.0就行。

vbnet 复制代码
        <key>LSMinimumSystemVersion</key>
        <string>13.0.0</string>

2、Asset validation failed (90236) Missing required icon. The application bundle does not contain an icon in ICNS format, containing both a 512x512 and a 512x512@2x image. For further assistance, see the Human Interface Guidelines at developer.apple.com/design/huma.... (ID: e0440ff7-4601-41cc-aeb4-7ea1e32560d2)

原因: 缺失应用图标

解决: 按照要求添加即可,在这里推荐一款 "免费生成iPhone、iPad、Mac OS平台应用Icon的Mac App:AppIcon Maker(xcAsset Creator)"

3、ITMS-90889: Cannot be used with TestFlight because the bundle at 'MyApp.app' is missing a provisioning profile. Main bundles are expected to have provisioning profiles in order to be eligible for TestFlight.

原因: .app/Contents路径下缺失发布环境的.provisionprofile文件。

解决:

1)在.entitlements文件中添加TeamID和AppID

2)在XXX.app/Contents/ 路径下添加 embedded.provisionprofile 文件

下面是我对苹果官方文档的学习和理解:

3、了解Mac 签名

3.1 公证Mac App

1)通过Mac App Store 分发的 Mac App,无须公证,因为在提交过程App Store已经对其进行了相同的安全检查。

2)非Mac App Store 分发的 Mac App,需要公证,否则会提示用户"应用可能会损害电脑"等,

3)问答:Mac 公证服务团队答疑

3.2 代码签名

  1. 所有的Mac App,都必须进行代码签名。

    • 如果使用Unity 编译导出.app文件,则需要手动为代码签名,也就是为.app进行签名
  2. 确定可执行文件

    根据file 指令,查看对应的文件是否为main executable,A main executable says Mach-O ... executable.

    arduino 复制代码
    $ file /Applications/XXX.app/Contents/PlugIns/AkSoundEngine.bundle/Contents/MacOS/AkSoundEngine
    /Applications/XXX.app/Contents/PlugIns/AkSoundEngine.bundle/Contents/MacOS/AkSoundEngine: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit bundle x86_64] [arm64]
    /Applications/XXX.app/Contents/PlugIns/AkSoundEngine.bundle/Contents/MacOS/AkSoundEngine (for architecture x86_64): Mach-O 64-bit bundle x86_64
    /Applications/DynastyLegends2.app/Contents/PlugIns/AkSoundEngine.bundle/Contents/MacOS/AkSoundEngine (for architecture arm64):  Mach-O 64-bit bundle arm64
    ​
    # 根据打印,可知AkSoundEngine不是main executable
  3. 决定签名顺序

    需要从内向外签署代码,也就是如果组件 A 依赖于组件 B,则先签署 B,然后再签署 A。

    举例:DaemonWithApp 产品有以下内容: ConfigApp.app, Core.framework, Share.appex, and Daemon,签名顺序应为:Core.frameworkShare.appexConfigApp.app,daemon是独立的,签名顺序随意。

  4. 配置权限文件

    代码签名可以包含App权限文件 .entitlements ,当 macOS 运行一个进程时,entitlements文件会授予该进程可执行文件在代码签名所包含的权限。

  5. 嵌入distribution provisioning profile

    在entitlements声明的权限,一般必须都需要在distribution provisioning profile中进行授权。当然也有一些不需要在distribution provisioning profile授权,就可以在entitlements中应用的权限。

    注意:一定要将distribution provisioning profile文件放在 XXX.app/Contents/ 路径下,且修改文件名为embedded.provisionprofile

  1. 确定代码签名的正确性

    ini 复制代码
    % codesign -d -vv <filePath>
    ​
    codesign -d -vv /Applications/NTSDK.app/Contents/PlugIns/unitypurchasing.bundle
    Executable=/Applications/NTSDK.app/Contents/PlugIns/unitypurchasing.bundle/Contents/MacOS/unitypurchasing
    Identifier=com.unity.purchasing.unitypurchasing
    Format=bundle with Mach-O universal (x86_64 arm64)
    CodeDirectory v=20500 size=1200 flags=0x10000(runtime) hashes=28+5 location=embedded
    Signature size=4844
    Authority=TestFlight Beta Distribution
    Authority=Apple Worldwide Developer Relations Certification Authority
    Authority=Apple Root CA
    Info.plist entries=26
    TeamIdentifier=7A34BX8C5J
    Runtime Version=11.0.0
    Sealed Resources version=2 rules=13 files=1
    Internal requirements count=1 size=116
  2. 为每一种代码类型签名

    shell 复制代码
    % codesign -s <CodeSigningIdentity> <PathToExecutable>
    # 举例子:
    % codesign -f -s '3rd Party Mac Developer Application: HK Taihe Interactive Limited (7A34BX8C5J)'  "/Users/taihe/Desktop/NTSDK.app/Contents/Frameworks/libmonobdwgc-2.0.dylib"
    /Users/taihe/Desktop/NTSDK.app/Contents/Frameworks/libmonobdwgc-2.0.dylib: replacing existing signature
    % codesign -f -s '3rd Party Mac Developer Application: HK Taihe Interactive Limited (7A34BX8C5J)'  "/Users/taihe/Desktop/NTSDK.app/Contents/Frameworks/UnityPlayer.dylib"
    /Users/taihe/Desktop/NTSDK.app/Contents/Frameworks/UnityPlayer.dylib: replacing existing signature
    % codesign -f -s '3rd Party Mac Developer Application: HK Taihe Interactive Limited (7A34BX8C5J)'  "/Users/taihe/Desktop/NTSDK.app/Contents/Frameworks/libMonoPosixHelper.dylib"
    % codesign -f -o runtime -s '3rd Party Mac Developer Application: HK Taihe Interactive Limited (7A34BX8C5J)' --entitlements "/Users/taihe/Desktop/App.entitlements" "/Users/taihe/Desktop/NTSDK.app"
    /Users/taihe/Desktop/NTSDK.app: replacing existing signature

    说明:

    1、不能对库代码进行包含权限文件(.entitlements)的代码签名,它会阻止可执行文件的程序运行,导致mac app打开就crash。

    2、不能使用sudo 运行 codesign,因为codesign在签署代码时依赖用户账户信息,使用sudo等工具会更改用户账户,从而造成一些意外情况.

    3、如果要签署包含权限的可执行文件,需要添加 --entitlements <entitlementsPath>,其中 <entitlementsPath> 是为该可执行文件创建的权限文件的路径。

    4、如果使用Developer ID 进行代码签名,需添加 --timestamp 选项,以包含安全时间戳。

    5、如果使用Developer ID 进行代码签名,需添加 -o runtime 选项,启用加固运行时。

  3. 避免使用--deep

    签署代码时,不要在 codesign 中使用--deep 选项。--deep会对其签署的每个代码项应用相同的entitlements。例如,如果你有一个内嵌命令行工具的应用程序,而应用程序和工具需要不同的权限,那么 codesign --deep 就会对两者应用相同的权限。

3.3 决定以什么样的格式分发Mac App

在Mac 上安装的应用支持四种格式:

  1. 从 Mac App Store上下载的直接就是.app

  2. 从非 Mac App Store上下载安装的可能是:

    以下3种格式可以嵌套

4、Entitlements

描述可执行文件的权限信息的文件,我一般叫它权限文件,内容以key-value形式展示。在对应用程序进行代码签名时,Xcode 会将权限文件、开发者账户中的信息以及其他项目信息结合起来,为应用程序应用一组最终的权限。

4、参考链接:

Packaging Mac software for distribution

Resolving Library Loading Problems

Creating Distribution-Signed Code for Mac

TestFlight, Provisioning Profiles, and the Mac App Store

相关推荐
HerayChen1 小时前
HbuildderX运行到手机或模拟器的Android App基座识别不到设备 mac
android·macos·智能手机
hairenjing11231 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
小李飞刀李寻欢3 小时前
Mac电脑如何解压rar压缩包
macos·rar·解压
Java小白笔记3 小时前
Mac中禁用系统更新
macos
AndyFrank3 小时前
mac crontab 不能使用问题简记
linux·运维·macos
Mac新人3 小时前
一招解决Mac没有剪切板历史记录的问题
macos·mac
王拴柱4 小时前
Mac保护电池健康,延长电池使用寿命的好方法
macos·mac
daa204 小时前
macos中安装和设置ninja
macos
Java小白笔记5 小时前
Mac解决 zsh: command not found: ll
macos
小钱c76 小时前
Mac下安装Apache JMeter并启动
jmeter·macos·apache