一文带你读懂何为 macOS App 公证,以及如何自动化实现

news2024/11/23 20:23:25

前言

在上篇文章「macOS App 自动化分发 App Store 探索与实践」中讲解了如何通过 Shell 脚本实现 macOS App 自动化分发 App Store。相信,看过的同学都或多或少对 macOS App 构建、分发 App Store 相关的知识都具备了一定的认知。

而对于开发者来说,我们更多情况下可能会选择在网络上分发 App。但是,站在使用者的角度,如果下载的 App 没有经过 Apple Notary Service 公证(Notarizate)过,这在安装的时候系统则会提示“无法打开 xxx App,因为无法验证开发者”:

那么,这个时候的解决方法就是修改系统偏好——>安全性与隐私的设置,选择仍要打开该 App:

虽然,这样可以让使用者安装 App,但是,这并不是真正在解决这个问题的本质,从根上解决应该是让我们要分发到网络上的 App 通过 Apple Notary Service 公证(Notarizate),这样一来他人下载安装我们应用的时候则不会出现无法打开的提示,而是:

所以,今天本文也将围绕「macOS App 公证」展开如何通过手动或者自动化(Shell、工具)实现公证(Notarizate)过程。

1. 手动公证

首先,我们先了解下如何手动公证?手动公证过程可以通过 Xcode 提供的 GUI 界面操作完成。同样地,首先我们需要构建 .xarchive 文件:

构建完后,Xcode 会弹出窗口让你选择 Distribute App 或 Validate App,这里我们选择前者:

接着,不同于之前分发 App Store,我们需要选择 Developer ID,它表示的是在 App Store 之外分发 App:

然后,我们需要选择 Upload ——> Development Team -> Manually manage signing,此时需要选择 Develop ID 对应的 Distribution 证书和 Provisioning Profile:

最后,则选择 Next ——> Upload,然后则会将我们的 App 上传到 Apple Notary Service 进行公证,通过则会提示我们可以分发 App。

可以看到,使用 Xcode 公证 App 的过程和 App Store 分发大同小异,所以,在通过简单了解使用 Xcode 手动实现公证过程后,接下来,我们来认识下如何自动化实现公证的过程?

2. 自动化公证

自动化公证则指的是我们通过代码实现前面介绍到的使用 GUI 手动实现公证的过程,然后再根据实际情况集成到现有的 CI/CD 过程中。而现在社区中实现的可以对 macOS App 自动化公证的方式主要有这 4 种:

  • altool --notarize-app 使用的旧的 Apple Notary Service,适用于 Xcode 12 以及更早的版本,但是需要注意的是Apple 将会在 2023 年秋季停止对它的支持
  • notarytool 使用的新的 Apple Notary Service,只适用于 Xcode 13 及以上的版本,相比较 altool --notarize-app 快了 10 倍
  • electron-notarize 用 JavaScript 实现的用于公证的工具,支持 notarytoolaltool --notarize-app 等 2 种公证方式
  • fastlane 用 Ruby 实现的一个可以便捷地帮你完成证书管理、代码签名和发布等相关的工具,适用于 iOS、macOS 和 Android 应用

所以,下面将会一一对这 4 个的使用做对应的展开介绍,首先是 altool --notarize-app

2.1 altool --notarize-app

在上篇文章「macOS App 自动化分发 App Store 探索与实践」中,我们介绍到可以使用 altool 对应用进行分发 App Store 和公证处理。

altool --notarize-app 也是最早大家使用的实现自动化公证应用的方式,这在社区中也可以看到大量基于它的实践。

altool --notarize-app 主要是将应用上传到 Apple Notary Service,但是并不会告知你公证成功与否,所以通常需要结合 altool --notarization-info 命令一起使用(核对公证成功与否),整个公证的过程会是这样:

可以看到,首先我们需要使用 altool --notarize-app 将应用上传公证,然后获取本次公证的 UUID:

xcrun altool --notarize-app \
# .app 的压缩包或 .dmg
--file ./Output/Apps/FEKit.zip \
--primary-bundle-id "com.xxxx.xxxx" \
# Apple ID
--username "xxxxx" \
# 应用专用密码
--password "xxxxx" \ 

然后,终端中则会输出本次公证上传操作的信息和 RequestUUID,前者用于表示本次操作执行是否成功,后者可以用于 altool --notarization-info 命令查询本次公证过程的信息:

No errors uploading 'Output/Apps/FEKit.zip'.
RequestUUID = xxxxxxx-xxx-xxxx-xxxx-xxxxx 

进行完公证上传操作后,Apple Notary Service 则会对本次公证执行相关的操作,而这需要一定的时间,所以我们需要(定时)轮询执行 altool --notarization-info 命令实时地获取公证成功失败与否的信息

# 加载 Apple ID($user)和 App 专用密码($pwd)
source "./Build/app_store_user_pwd.sh"

# 标识公证执行过程成功失败与否,失败 1,0 成功
success=1
i=0
while true; dolet i+=1echo "Checking notarize progress...$i"# 获取 altool --notarization-info 执行的输出信息process=$(xrun altool --notarization-info $uuid --username $user --password $pwd 2>&1)echo "${progress}"# 如果上次命令执行结果 $? 不等于 0(表示失败),或者命令输出信息中包含 Invalidif [ $? -ne 0 ] || [[ "${progress}" =~ "Invalid"]] thenecho "Error with notarization. Exiting"breakif# 如果命令输出信息中包含 success 表示成功if [[ "${progress}" =~ "success"]]; thensuccess=0breakelseecho "Not completed yet. Sleeping for 30 seconds.\n"fisleep 30
done

if [ $success -eq 0 ]; thenecho "Notarize successed."
if 

其中,$uuid 则是执行 altool --notarize-app 命令后获取的返回结果:

echo xcrun altool --notarize-app \
--file xxxx \
--primary-bundle-id "com.xxxx.xxxx" \
--username $user \
--password $pwd \
2>&1 | grep RequestUUID |awk '{print $3}' 

这里我们来看下大家比较陌生的 2>&1grep RequestUUIDawk '{print $3}' 等 3 个命令的作用:

  • 2>&1 是为了将标准错误 stderr 输出重定向到标准输出 stdout
  • grep RequestUUID 匹配标准输出中所有包含 RequestUUID 的行
  • awk '{print $3}' 打印出第 3 列的结果,在 RequestUUID = xxxxxxx-xxx-xxxx-xxxx-xxxxx 就是 RequestUUID 的值 xxxxxxx-xxx-xxxx-xxxx-xxxxx
  • | 管道,用于将上个命令的输出通过管道输入到下一个命令

2.2 notarytool

相比较 altool --notarization-info 而言,notarytool 使用起来心智负担少一些,并且快于前者很多,我们只需要记忆一些 Option,使用一行命令 xcrun notarytool 则可以实现上传公证和过程信息获取的过程:

xcrun notarytool submit ./Output/Apps/FEKit.zip \
# Apple ID
--apple-id $user \
--team-id $teamId \
# 应用专用密码
--password $pwd \
-v \
-f "json" 

其中,--team-id 指的是用户 ID(由数字和字母组成),这可以在本地 KeyChain 的证书中查看(或者 Apple 证书后台),-v--verbose 的缩写,指的是输出公证过程的信息,-f "json" 则是表示最终结果以 JSON 的格式输出,例如:

{"path":"\/Users\/wujingchang\/Documents\/project\/demo\/FEKit\/Output\/Apps\/FEKit.zip","message":"Successfully uploaded file","id":"xxxxxxxxxxxxxxxxxxxx"
} 

需要注意的是这里使用的是 Appple ID 和应用专用密码的方式做与公证服务的请求认证 Authentication,此外你还可以通过以下 3 种 Option 来进行认证:

  • --keychain-profile <keychain-profile>,使用 xcrun notarytool store-credentials 预先在本地钥匙串中新建一个应用程序密码,例如叫 AC_PASSWORD,那么在使用 notarytool submit 命令的时候则可以直接使用 --keychain-profile AC_PASSWORD 代替之前的 --apple-id $user --team-id $teamId --password $pwd
  • --keychain <keychain>,不同于前者 --keychain-profile 这里是输入的 AC_PASSWORD 文件所在的位置
  • --key <key-id> --key-id <key-id> --issuer <issuer>,这使用的是 App Store Connect API keys 的方式进行认证,本质上是生成一个和 App Store Connect 约定好的 JWT,然后每次请求的时候携带上它,从而通过认证

2.3 electron-notarize

electron-notarize 则是一个用 JavaScript 实现的公证工具,它的原理则是使用的 child_process 执行前面我们提及的 altool --notarization-infonotarytool 这 2 个命令。

electron-notarize 具名导出了 notarize 函数,我们只需要使用它以及指定的 Option 则可以完成公证的过程,这里我们来看下其函数的实现(伪代码):

// src/index.ts
export async function notarize({ appPath, ...otherOptions }: NotarizeOptions) {if (otherOptions.tool === 'notarytool') {// ...await notarizeAndWaitForNotaryTool({appPath,...otherOptions,});} else {// ....const { uuid } = await startLegacyNotarize({appPath,...otherOptions,});// ...await delay(10000);// 获取公证过程信息await waitForLegacyNotarize({ uuid, ...otherOptions });}await stapleApp({ appPath });
} 

可以看到,notarize 函数会根据 Option 中传入的 toolnotarytoollegacy 来执行不同的命令来完成公证,这里前者是 notarytool 后者则是 altool --notarization-info。所以,如果我们要用 notarytool 的方式进行公证会是这样:

import { notarize } from "electron-notarize"

await notarize({appPath: "./Output/Apps/FEKit.zip",// Apple IDappleId: "xxxxxx",// 应用专用密码appleIdPassword: "xxxxxxxx",teamId: "xxxxxxxxxxx",tool: "notarytool"
}) 

其中,如果你不希望密码直接明文暴露在代码中的话,electron-notarize 也支持了前面我们说的 --keychain--keychain-profile 等 3 个 Option,你可以根据自己的需要选择对应的认证方式。

2.4 fastlane

fastlane 是一个可以便捷地帮你完成证书管理、代码签名和发布等相关的工具,适用于 iOS、macOS 和 Android 应用。那么,我们也就可以使用 fastlane 来完成 macOS App 的公证。

首先,肯定是安装 fastlane,关于这方面的介绍官方文档讲解的很是详尽,这里就不重复论述。而当你安装好 fastlane,则可以在应用项目的根目录执行 fastlane init 来初始化它相关的配置,在初始化的过程会让你选择使用 fastlane 的方式,这里我们选择手动配置即可。

然后,它会在项目根目录下创建一个 fastlane/Fastfile 目录和文件,后续我们在执行 fastlane xxx 命令的时候则会根据该文件的代码实现执行具体的操作,默认生成的 Fastfile 文件的配置会是这样:

default_platform(:ios)

platform :ios dodesc "Description of what the lane does"lane :custome_lane do# add actions here: https://docs.fastlane.tools/actionsend
end 

其中,default_platform 用于定义一个默认的平台 Platform,例如当我们有 2 个平台(iOS 和 macOS)的时候,它的的配置需要这样:

default_platform(:ios)

platform :ios dodesc "Description of what the lane does"lane :custome_lane do# add actions here: https://docs.fastlane.tools/actionsend
end
platform :mac dodesc "Description of what the lane does"lane :custome_lane do# add actions here: https://docs.fastlane.tools/actionsend
end 

此时,如果我们执行 fastlane custome_lane,由于这里平台默认为 ios,所以则会执行 platorm:ios 下的 custome_lane,反之执行 fastlane mac custome_lane,则是 platform :mac 下的 custome_lane。那么,对于前面我们这个例子而言只需要 platform:mac

default_platform(:ios)

platform :mac dodesc "Description of what the lane does"lane :custome_lane do# add actions here: https://docs.fastlane.tools/actionsend
end 

接着,则可以在 platform:mac 写我们需要实现的自动化分发 App Store 相关的代码。fastlane 便捷之处在于它实现了很多开箱即用的 Action,这里我们需要使用 notarize 这个 Action,它可以用于完成 macOS App 的公证:

default_platform(:mac)

platform :mac dodesc "Notarizes a macOS app"lane :notarize_app donotarize(package: "./Output/Apps/FEKit.zip",use_notarytool: "xcrun notarytool",bundle_id: "com.xxxx.xxxx",username: "xxxxxxxxxxxxxx",verbose: true,)end
end 

其中,在使用 notarize 的时候需要注意的是,这里只是声明了你 App Store 的用户名 username,而专用密码需要预先在系统环境变量中添加 FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD(其他认证方式,有兴趣的同学可以自行了解),然后 fastlane 在执行 notarize_app Action 时会去读取该环境变量,从而进行并完成后续的公证过程。

结语

看到这里,我想可能会有同学会问:“这几种实现公证的工具,选择哪个比较好?”,这里比较建议的是选择 fastlane,因为,除开前面提及它的使用方式非常便捷的优点,它具备的能力也很多,不仅仅可以做 App 公证,还可以做 App Store 分发、证书和版本管理等,所以,选择 fastlane 将来也可以支持我们别的诉求,何乐不为呢?

最后,如果文中存在表达不当或错误的地方,欢迎各位同学提 Issue ~

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91517.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RCE(远程代码/命令执行漏洞)原理及靶场练习

目录 PHP-RCE涉及函数 基础命令符 靶场练习 PHP-RCE涉及函数 代码注入 eval() 把字符串 code 作为PHP代码执行 assert() 检查一个断言是否为 false preg_replace() 执行一个正则表达式的搜索和替换 create_function() 创建一个匿名函数并且返回函数名创 call_user_func()/ca…

Android进程启动流程

一.Android 系统架构图 ​虽然 Android 系统非常庞大且错综复杂&#xff0c;但整体架构设计清晰。Android 底层内核空间以 Linux Kernel 作为基石&#xff0c;上层用户空间由 Native系统库、虚拟机运行环境、框架层组成&#xff0c;通过系统调用(Syscall)连通系统的内核空间 与…

浅谈hudi 的callback回调机制

浅谈hudi 的callback回调机制 关于hudi的write operations,hudi有4种类型,分别为upsert/insert/bulk_insert/delete[软删除/硬删除]。 了解hudi的都知道,hudi有一个核心的机制就是timeline,hudi的instantDTO包含action(动作),ts(时间),state(状态)。 action主要包括: commits…

Linux常用命令总结(建议收藏)

文章目录一、文件管理1、cat&#xff1a;查看文件内容案例1&#xff1a;输出内容行数2、chmod&#xff1a;是控制用户对文件的权限的命令案例1&#xff1a;&#xff1a;将user文件修改成用户、组、其他用户都可以读写可执行的权限3、diff&#xff1a;用于比较文件的差异4、find…

ELK (一)部署ELK+Filebeat日志收集分析系统

说明&#xff1a;此安装流程只适用于8.0.0以下的版本 1. ElasticSearch 部署 1.1 下载ElasticSearch的wget指令&#xff1a; wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.13.4-linux-x86_64.tar.gz1.2 解压安装包到指定目录 指定解压缩到 …

【指纹识别】指纹识别【含GUI Matlab源码 586期】

⛄一、指纹识别简介 1 指纹识别的引入和原理 1.1 指纹的基本知识 指纹&#xff0c;由于其具有终身不变性、唯一性和方便性&#xff0c;已几乎成为生物特征识别的代名词。指纹是指人的手指末端正面皮肤上凸凹不平产生的纹线。纹线有规律的排列形成不同的纹型。纹线的起点、终点…

SpringBoot+Vue实现前后端分离的旅游网站

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

【Effective_Objective-C_2对象,消息,运行期1】

文章目录前言6 理解”属性“这一概念定义变量不兼容现象的出现解决不兼容现象-Property使用属性更便捷属性特质原子性读写权限内存管理语义方法名原子性和非原子性要点总结7 在对象内部尽量直接访问实例变量要点总结8 理解“对象等同性” 和 isEqual“” 判断的依据“isEuqalTo…

RTL8380M/82M管理型交换机系统软件操作指南四:QoS/服务质量

接下来对QoS进行详细的描述&#xff0c;主要包括以下七大内容&#xff1a;QoS概述、功能简介、拥塞管理、策略分类、调度方式、优先级映射配置、QoS端口配置. 1.1 QoS概述 QoS&#xff08;Quality of Service&#xff0c;服务质量&#xff09;是用各种手段解决网络延迟和阻塞等…

[附源码]Python计算机毕业设计SSM基于Java动漫论坛系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

业务模型设计

业务模型设计业务模型设计统一语言、术语统一单词业务数据表模型规范数据库范式几个经验业务模型索引主键&#xff1a; 自增id、雪花id、和uuid 差别创建表字符集设置myisam 和 innodb 区别业务模型设计 统一语言、术语 定义&#xff1a;需求分析的过程&#xff08;系统目标、…

001、【C语言编程题目】猴子吃桃问题

001、【题目】猴子吃桃问题 猴子吃桃问题&#xff1a;猴子第一天吃了若干个桃子&#xff0c;当即吃了一半&#xff0c;还不解馋&#xff0c;又多吃了一个&#xff1b; 第二天&#xff0c;吃剩下的桃子的一半&#xff0c;还不过瘾&#xff0c;又多吃了一个&#xff1b;以后每天…

艾美捷针对性检测—游离维多珠单抗ADA水平检测试剂盒

艾美捷游离维多珠单抗ADA水平检测试剂盒可靠地测定游离ADA针对维多利单抗&#xff08;如ENTYVIO&#xff09;). 风湿因子的联合测定或排除不规则抗体。连同确定维多利单抗的活性物质浓度由IDK监测仪指示 维多利单抗免费ADA ELISA&#xff0c;主治医师有可能陪同治疗并在早期阶段…

用Python作一条已知曲线的等距曲线

参考资料&#xff1a; 该如何作一条已知曲线的等距曲线&#xff1f; - 知乎 等距线_百度百科 目录 1.等距线 2.数学推导 3.示例 4.代码与结果 1.等距线 等距线&#xff08;equidistant line&#xff09;亦称平行曲线&#xff0c;一种平面曲线&#xff0c;即由一已知曲线…

准备Plan B 如何设计兜底方案

对于很多秒杀系统而言&#xff0c;在诸如双十一这样的大流量的迅猛冲击下&#xff0c;都曾经或多或少发生过宕机的情况。当一个系统面临的大流量时&#xff0c;它其实很难单靠自身调整来恢复状态&#xff0c;你必须等待流量自然下降或者认人为地把流量切走才行&#xff0c;这无…

Android OpenGL ES 学习(九) – 坐标系统和实现3D效果

OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学习(三) – 绘制平面图形 Android OpenGL ES 学习(四) – 正交投影 Android OpenGL ES 学习(五) – 渐变色 Android OpenGL ES 学习(六) – 使用…

高通Ride软件开发包使用指南(7)

高通Ride软件开发包使用指南&#xff08;7&#xff09;6.5 构建 x86 Ubuntu SDK6.6端到端可视化6.7 x86 Ubuntu上的功能验证6.7.1简单比特率验证6.7.2在x86笔记本上用 8xCams HEVC格式 录制 FPS6.8记录仪6.5 构建 x86 Ubuntu SDK 构建 x86 ubuntu ~/src/qride/stack-sdk$ ./ex…

十个精妙绝伦的SQL语句,说尽SQL精华

目录引子十大SQL1. 统计班级总分前十名2. 删除重复记录, 且保留一条3. 最大连续登陆天数的问题4. 计算除去部门最高工资&#xff0c;和最低工资的平均工资5. 计算占比和同比增长6. 算成绩7.算昨天每个城市top 10消费金额的用户&#xff0c;输出city_id,city_name,uid, 消费总金…

C语言刷题(3)

&#x1f412;博客名&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;别人可以拷贝我的模式&#xff0c;但不能拷贝我不断往前的激情 目录 计算体重指数 计算三角形周长和面积 KiKi和酸奶 网购 变种水仙花 计算体重指数 描述 问题&#xff1a;计算BMI指数&#xff0…

安全可信 | 强墙出击!天翼云Web应用防火墙(原生版)硬核亮相!

12月9日&#xff0c;由中国信息通信研究院主办的“墙墙联合——云上防火墙技术沙龙”在线上顺利举行&#xff0c;天翼云科技有限公司研发专家吴雷分享了新标准、新需求下云Web应用防火墙&#xff08;云WAF&#xff09;的发展方向&#xff0c;并介绍了天翼云Web应用防火墙&#…