iOS 持续集成:更完备的 App Store Connect API

引言

时隔两年 App Store Connect API 有了更新,WWDC 2018 推出了 App Store Connect API ,用于自动化一些 App Store Connect 后台操作。这次更新包含了 app 元数据相关的API,补上了原来缺失的重要一环, 使得几乎可以通过 App Store Connect API 完成 App Store Connect 上的所有操作。今后开发、证书配置、用户管理、测试、发布全流程都可以通过 API 完成。


需要注意的是, 配置应用内购买和 Game Center 还是需要通过App Store Connect 网站进行配置。

现有的解决方案

Fastlane 已经是一个完善的自动化工具,它提供了如 produce 等工具用于更新元数据。为啥还要关心 App Store Connect API 呢?

首先 App Store Connect API 是苹果官方提供的,适用于所有环境。Fastlane 基于 ruby 的,限制适用的技术栈。

其次 Fastlane 是通过 Spaceship 来访问 Apple Developer Center 和 App Store Connect 的。目前 Spaceship 是通过解析网页来实现自动处理的,会有以下几个问题:

  1. Apple Developer Center 和 App Store Connect 是两个不同的网站,因此需要两次认证,存两份cookie。
  2. 现在 Apple ID 强制开启了双重认证, 每次登录需要验证码,无法完全自动化。cookie 也只能保持 1 个月。
  3. Apple Developer Center 和 App Store Connect 如果有页面更新,Spaceship 就需要升级来适应变化。

如果都能够用 App Store Connect API 来实现,则这些问题就不存在了。

App Store Connect API 也有一些不完善的地方,例如 其 token 有效期只有 20 分钟,固然增强了安全性,但是如何签名产生这个 token,还需要总结出一个最佳实践。

瑕不掩瑜,业界对 App Store Connect API 还是蛮期待的。Fastlane 在 2.150.0 的分支中已经添加对新的 App Store Connect API 的支持。相关讨论 issue:Fastlane: Support new App Store Connect APIs[1]

App Store Connect API 的新内容

文档

这次新增了 200+ 的 RESTful endpoint, 和原来相比翻了一倍。苹果爸爸还将提供一个 openAPI 规范文件供您下载(OpenAPI Specification[2] 是流行的swagger格式的开放标准第三版)。可以在 swagger UI 中查看它,以获取快速的 API 参考。或者更好的方法是将其输入代码生成器中,以更快,更轻松地引导几乎所有语言的 API 集成。苹果爸爸还声称会添加了一些有关速率限制和文件上传等主题的新说明文章,提供可下载的示例代码,以演示重要的 API 概念,例如创建和签名身份验证令牌,与API响应进行交互以及使用新的资产上传 API。


。详情可以参考:App Store Connect API Resources[3]

应用元数据API (app metadata API)

Session Expanding automation with the App Store Connect API[4] 中 Geoff Coffey 是通过一个例子,贯穿讲解了 相关的 API,包括以下 5 个步骤:创建一个新版本,设置定价以更新应用程序元数据,将构建与该版本相关联,然后将该新版本提交给App Review 。本文就做一个简要的总结,不再一一列举了。

新API遵守原有的 App Store Connect API 的认证方式。可以参考文章 App Store Connect的新特性(WWDC 2018 session 301 & 303)[5], App Store Connect API[6]

基本规则

应用元数据的相关资源以及它们的关系如下图所示。


图中每个节点代表 restful api 中的一个资源,例如 /v1/apps。图中联线代表资源之间的关联,例如:一个 App 可以有多个 App Store Versions。每个资源的数据结构如下

data: {
    "type": 资源名,
    "id": 资源ID,
    "attributes": {
        资源自己的属性
    },
    relationship: {
        "关联资源名": {
            "data" : { "type": 资源名, "id": 资源ID }
        }
    }
}

查询资源

通过 GET 方法 请求资源路径就可以获得对应资源的元数据。

可以通过添加形如 filter[key]=value 的 query string 来过滤返回的结果。例如:

GET /v1/apps?filter[bundleID]=org.forestexplorer.ForestExplorer
GET /v1/builds?filter[app]=appid&filter[perReleaseVersion.version]=1.1&fileter[version]=3

此时返回结果 data 是一个数组。

可以通过指定资源的 ID,来确定的获得一个资源的数据。例如:

GET /v1/apps/资源ID

此时返回结果 data 是一个对象。

当然也可以获取一个确定资源的关联资源。例如:

GET /v1/appStoreVersions/资源ID/appStoreVersionLocalizations
GET /v1/appStoreVersionLocalizations/资源ID/appPreviewSets

可以通过添加include=关联资源名的 query string 来让返回结果同时包含关联资源, 例如:

GET /v1/apps/资源ID/prices?include=priceTier

修改资源

修改资源通过 http 的 patch 方法。路径需要指定对应的资源 ID。有意思的是,如果想要用一个原子操作,修改资源的同时为资源添加关联资源。而此时由于新添加的资源还没有创建,没有一个正式的资源 ID。可以通过 ${临时资源ID} 的方式由创建者临时指定一个资源 ID, 并在 data 的同级添加一个 included 其中包含临时资源 id。只要临时资源 ID 相同,就会关联并创建。在返回结果中会更正为真正的资源 ID。例如

PATCH /v1/apps/资源ID/
{
    "data": {
        "type": "apps",
        "id": 资源ID,
        "relationships": {
            "prices": {
                "data" : [{ "type": "appPrices", "id": "${tmpid}" }]
            }
        }
    },
    "included": [{
        "type": "appPrices",
        "id": "${tmpid}",
        "attributes": {
        },
        "relationships": {
            "priceTier": {
                "data": { "type": "priceTiers", "id": "0" }
            }
        }
}

当然也可以直接修改一个资源的关联资源,例如修改一个appStoreVersion 关联的build

PATCH /v1/appStoreVersions/资源ID/relationships/build

创建资源

一个典型的例子是在 AppStore 添加一个新的版本:

POST /v1/appStoreVersions

{
    "data": {
        "type": "appStoreVersions",
        "attributes": {
            "platform": "IOS",
            "versionString": "1.1"
        },
        "relationships": {
            "app": {
                "data": {"type" : "apps", "id" : "资源ID" }
            }
        }
    }
}

创建新资源不用添加"id"属性,创建成功后,ID会自动生成,并在结果中返回

appPreviewsappScreenshots 不仅仅包含元数据,还包含具体的图片、视频文件,这些怎么上传呢?图片、视频文件被统一叫做 asset,代表大数据文件。 在创建 appPreviewsappScreenshots 的元数据成功后,服务端会返回一个属性字段 "uploadOperations" 其中包含了上传 asset 的相关信息。例如 urlmethodoffsetlength,以及请求的headers。使用者还需要通过这些信息上传asset。

需要注意的是, "uploadOperations" 可能返回一个数组,这样可以将大文件分段上传。上传的顺序可以打乱,也可以并发上传,其中一块失败了只需要重传失败的块就行了。


当所有块都上传成功后,还需要更新一下 appPreviews 元数据的状态。标记 uploadedtrue 并且附上 sourceFileChecksum。app store connect 会对上传的asset再做处理。这个处理是异步的。需要通过查询 appPreview 的元数据来确认处理状态。

诊断数据API (Power and Performance Metrics and Diagnostics API)


诊断数据API获取的数据是显示在Xcode中的功能和性能视图(上图)中的数据。有另外一个session: Identify trends with the Power and Performance API[7] 详细讲解其中的具体数据内容。

诊断数据可以通过 app 或者 build 维度获取,具体路径形如:

GET /v1/apps/资源ID/perfPowerMetrics
GET /v1/builds/资源ID/perfPowerMetrics

这里由于返回的数据是苹果定制的格式,因此需要在请求头中添加accept类型如下:

accept: application/vnd.apple.xcode-metrics+json

特别指出,在磁盘写入时,会包含一些堆栈信息,因此还有一个diagnosticSignature的资源节点以及关联的logs资源节点

GET /v1/builds/资源ID/diagnosticSignatures
GET /v1/diagnosticSignatures/资源ID/logs

总结

新的 app metadata API 提供了一种官方支持的自动化发布app的方案。大家可以开动想象力,发挥它的潜力。例如,通过这些 API 一些面向企业的 APP 都可以高效的自动生成定制化版本。再结合苹果正在推广的 Apple Business Manager ,定向为企业发布定制化版本的app。或者未来会涌现出一些简化开发的平台,提供模板和上线服务。只要你有创意和资源,就可以一键在AppStore 上发布一个应用了。


https://mp.weixin.qq.com/s/KnryMnySoOXvf8K7kQVwmA

iOS中的内嵌汇编

写一篇在iOS上使用汇编的文章的想法在脑袋里面停留了很久了,但是迟迟没有动手。虽然早前在做启动耗时优化的工作中,也做过通过拦截objc_msgSend并插入汇编指令来统计方法调用耗时的工作,但也只仅此而已。刚好最近的时间项目在做安全加固,需要写更多的汇编来提高安全性(文章内汇编使用指令集为ARM64),也就有了本文

发布于:10天以前  |  54次阅读  |  详细内容 »

不会吧,这也行?iOS后台锁屏监听摇一摇

一般情况下,出于省电、权限、合理性等因素考虑,给人的感觉是很多奇怪的需求安卓可以实现,但是iOS就无法实现!今天要介绍的需求也有这种感觉,就是“当 APP 处于后台或锁屏状态时,依旧可以监听到摇一摇,进而触发某些功能,比如:语音播报”。

发布于:1月以前  |  121次阅读  |  详细内容 »

iOS 稳定性:App 被终止的原因

本次 session 主要内容如下: 介绍了后台应用终止的常见原因,并提供了一些优化建议 介绍了 MetricsKit 提供的在代码中获取诊断和性能数据的方法 介绍了 Xcode Metrics Ogranizer 提供的关于线上用户性能数据的可视化报告

发布于:1月以前  |  150次阅读  |  详细内容 »

Vue中Axios的封装和API接口的管理

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御XSRF等。所以我们的尤大大也是果断放弃了对其官方库vue-resource的维护,直接推荐我们使用axios库。如果还对axios不了解的,可以移步axios文档。

发布于:1月以前  |  153次阅读  |  详细内容 »

iOS 持续集成:更完备的 App Store Connect API

时隔两年 App Store Connect API 有了更新,WWDC 2018 推出了 App Store Connect API ,用于自动化一些 App Store Connect 后台操作。这次更新包含了 app 元数据相关的API,补上了原来缺失的重要一环, 使得几乎可以通过 App Store Connect API 完成 App Store Connect 上的所有操作。今后开发、证书配置、用户管理、测试、发布全流程都可以通过 API 完成。

发布于:1月以前  |  190次阅读  |  详细内容 »

iOS 性能优化:优化 App 启动速度

苹果是一家特别注重用户体验的公司,过去几年一直在优化 App 的启动时间,特别是去年的 WWDC 2019 keynote[1] 上提到,在过去一年苹果开发团队对启动时间提升了 200%

发布于:1月以前  |  178次阅读  |  详细内容 »

让你的应用远离越狱:iOS 14 App Attest 防护功能

当越狱在 iOS 设备第一次流行起来时,iOS 开发人员会尝试各种方法来保护自己的应用程序,以让应用免受盗版等不确定因素的困扰。有许多方法可以做到这一点,包括检查 Cydia 是否存在、检测应用程序是否可读取自身沙箱之外的文件、在检测到调试器时让应用程序崩溃等等。

发布于:1月以前  |  195次阅读  |  详细内容 »

探秘 iOS 14 的 WidgetKit

Widget Extension 提供了 small, medium, large 三个尺寸,不同尺寸可以展示不同的数据、不同的界面,开发者也可以锁定自己APP的 Widget 只有某类尺寸,相同的widget也能重复添加。作为添加在主屏幕上的控件,苹果用了 “At a glance” 来形容 widget ,所以 widget extension 是无法交互的,它能做的只有展示一些信息与点击两个作用,点击后就会引导至app,同时为了性能与耗电量的考虑,Widget extension 也不能展示视频和动态图像。

发布于:1月以前  |  211次阅读  |  详细内容 »

iOS14 Widget 万字指北,先人一步获得顶级流量

2020 年 6 月 22 日,苹果召开了第一次线上的开发者大会 - WWDC20。这次发布会上宣布了ARM架构Mac芯片(拳打Intel)、iOS 14 ATT(脚踢Facebook),可谓是一次载入史册(我是爸爸)的发布会了,当然还发布了被称为下一个顶级流量入口的Widget。踩着八月的尾巴,本次我们就来探究一下Widget。本文会从Widget初窥和Widget开发两个维度和章节来探究一下Widget, 其中初窥章节会带您简单的了解一下Widget,适合应用决策者阅读; 开发章节会带着您一步一步的完成设计开发Widget,适合程序员阅读。

发布于:1月以前  |  264次阅读  |  详细内容 »

OCRunner:完全体的iOS热修复方案

为了能够实现一篇文章的思路:Objective-C源码 -> 二进制补丁文件 ->热更新(具体是哪篇我忘了)。当时刚好开始了oc2mango翻译器的漫漫长路(顺带为了学习编译原理,嘻嘻),等基本完成以后,就开始肝OCRunner:完全兼容struct,enum,系统C函数调用,魔改libffi,生成补丁文件等,尽可能兼容Objective-C,为了做一个直接运行OC的快乐人。

发布于:1月以前  |  219次阅读  |  详细内容 »

iOS APP图标版本化

在我们的项目开发过程中,需要频繁打包给测试人员去测试,有时候我们都不知道测试机上安装的版本是否是最新的,这样会造成很多不必要的麻烦和成本。因此我们需要将buildNumber以水印的方式打在APPIcon上,可以很直观的知道当前是哪一个版本。

发布于:1月以前  |  206次阅读  |  详细内容 »

百度App iOS工程化实践: EasyBox破冰之旅

百度App从单一的搜索工具发展到今天以搜索和Feed流为双引擎的综合性内容消费服务平台,其复杂程度已然不可同日而语矣。 作为一个日活过亿的超级App,业务规模庞大,相关技术人员超过千人,客户端支持主流的移动技术,涉及近百业务方,技术形态复杂,各种组件近三百个,代码百万量级,由此带来的工程化问题是技术团队的一个极大挑战。

发布于:1月以前  |  227次阅读  |  详细内容 »

最多阅读

快速配置 Sign In with Apple 1年以前  |  3443次阅读
开篇 关于iOS越狱开发 1年以前  |  2454次阅读
给数组NSMutableArray排序 1年以前  |  2404次阅读
APP适配iOS11 1年以前  |  2376次阅读
在越狱的iPhone设置上使用lldb调试 1年以前  |  2325次阅读
UITableViewCell高亮效果实现 1年以前  |  2229次阅读
使用 GPUImage 实现一个简单相机 1年以前  |  2220次阅读
App Store 审核指南[2017年最新版本] 1年以前  |  2198次阅读
所有iPhone设备尺寸汇总 1年以前  |  2122次阅读
使用ssh访问越狱iPhone的两种方式 1年以前  |  2040次阅读
关于Xcode不能打印崩溃日志 1年以前  |  2013次阅读
使用ssh 访问越狱iPhone的两种方式 1年以前  |  1894次阅读
UIDevice的简单使用 1年以前  |  1737次阅读
为对象添加一个释放时触发的block 1年以前  |  1699次阅读
使用最高权限操作iPhone手机 1年以前  |  1663次阅读

Whoops, looks like something went wrong.