iOS AdHoc Signing && Distribution Website(Node.js,Bluemix)

14 Dec 2016 . category: engineering . Comments
#frontend

项目简介 Demo

移动端越来越火的今天,我的许多小伙伴也纷纷从 J2EE 的坑里跳出来投身 iOS 和 Android 的温暖怀抱。一路上小伙伴们也踩了很多坑,埋了很多雷.在这之中,应用发布问题的坑特别多,很多新人都会迷失在这点。尤其是在 iOS 平台,相比于安卓,由于苹果的严格管控导致 iOS App 的发布变成一个很麻烦的事情。比如你开发了一个有趣的 iOS 闹钟应用,想给你的朋友 🐻 同学安装秀一发。 你可以选择如下四种方法来给他装:

发布方法 评价
抱着你的 Mac,带着数据线去敲他家门 我就不多加赘述,如果 🐻 同学是个美丽的妹子,请直接采用。
使用官方的 Appstore AppStore 通常来说都要经过一个漫长的审核期,即使苹果已经尽量让这个过程无痛了。但是依然要一天左右的时间,同时还不保证一次就能通过,对自己代码及其自信而且有耐心的同学可以采用。
使用 TestFlight 的测试功能 官方推荐的测试方法,分为内部测试和外部测试两种。 外部测试和第二种方法一样,需要一天左右的审核期。 内部测试的话,只需要一封邮件确认(PS–这个经常会被自动归类到垃圾邮件),就可以得到下载链接,不过有一个最多 25 个人的限制。如果你需要秀一脸的同学不多,可以选择这个模式。 具体流程戳这里
使用 AdHoc 的方式导出 ipa 文件给他装 我接下来要介绍实现的方法, 她对拥有 Enterprise Certificate 的人特别友好。 通过这种方法,没有人数限制,没有审核时间,可以通过访问网站直接安装到 🐻 同学的手机上。 如果你没有 Enterprise Certificate, 你需要收集小伙伴们手机或者 iPad 的 UDID,具体方法戳这里

Pre Step

对于没有 Enterprise Certificate 的同学,请先跟着这一步初始化你的 provision profile。用 Enterprise Certificate 的同学会稍有不同。在 IBM,我们有一个自动 build + signing 的系统,只需要提交 xcode 项目,会直接生成一个用 Enterprise Cert 签名好的 ipa 文件。 如果你有直接使用 Enterprise Cert 的权限可以直接跳到 Step1

首先你要有一个开发者账户,如果没有出门左转

登录进你的开发者账户,会看到如下页面, 我们这里假定你的 Mac 有 signning 的 certificate,如果没有请戳这里. 这个是保证你的电脑有给 ipa 签名的权力

image

接下来要进行三个动作

  1. 在左侧 menu 的 Device -> All 里面加入你收集到的 UDID

  2. 在左侧 menu 的 Identifier -> App IDs 里面加入你想 build 的 app 的 bundle ID (这个很关键)

  3. 在左侧 menu 的 Provisions Profiles -> All 里面新建一个跟你的 APP ID 绑定的 AdHoc Distribution 的 profile,这里会让你选择 certificate 来确保不会被盗用

下载这个 profile,你会得到一个 mobileprovision 文件,暂时大功告成,你得到了一个可以给 App 签名的文件,双击安装这个文件

Step 1 - 签名 ipa 文件

这里我们以 Xcode Version 8.2 (8C38)为例,经过上一步的 mobileprovision 文件的安装,在下图的所示的位置可以查看到 General -> Signing -> Team -> Add Account -> View Details

image

也可以在 General -> Signing -> ProvisionING Profile 里直接查看

image

接下来 Product -> Archive

image

然后选择 export -> Save for Ad Hoc Deployment, 有 Enterprise Cert 的同学选择 export -> Save for Enterprise Deployment

image

然后一路 next 下去, 记得选上 Generate Mainfest.plist,如果不必要不要选 rebuild from bitcode, 不然会很慢

image

在下一步里填上 website 的地址和 logo 地址,填错也没关系等下可以手动改文件。

image

Archive 之后你会得到一个 ipa 和一个 mainfest.plist 文件

Step 2 - Distribution 网站开发

这一步我们就要开始开发我们的网站,需要下载的 Sample Code 在这里 Github. 这个 repo 可以当作是一个 start point,你只需要改两个地方:

  1. config.js
  2. app/

这是网站的结构和对各个相关文件的说明

image

文件 说明
app/ 用来放生成的 ipa 和 mainfest.plist 文件
public/ 网站相关静态文件,用了 ejs 模版来生成 html
app.js web server 主入口
config.js 配置文件,需要根据自己的 distribution 网站来改动里面的 appName 和 web url,很关键,必须要改不然网站会失效
config.js(需要改)

把这个文件里的两个属性改成你网站对应的

const config = {
  APP_NAME: "TestDistribution",
  WEB_URL: "https://sample-ios-distribution.au-syd.mybluemix.net",
};

app/(需要改)

把这个文件夹里的 ipa 和 mainfest 文件替换

mainfest.plist,这个文件是整个下载的核心,可以手动修改,在其中有几个关键点要注意下。

  • 下面的三个 item 一定要保证跟你的网站网址对应,而且图片大小也是能对的上的。这个图片会在用户下载时显示在 loading 上

    1. URL
    2. Display-image
    3. Full-size-image
  • bundle-identifier 一定要和 App 保持一致

app.js

Code 很简单,但是有一个小坑说明下。Apple 规定,iOS 设备不能直接下载 ipa 文件,必须通过 plist 文件的指引来下载。

所以我们首先定义 Plist 和 ipa 的位置,然后在 download-app API Endpoint 中发送 Plist. Plsit 文件会将 request 导向其所定义的 appPath URI, 然后我们在相应的 API Endpoint 中发送 ipa 文件。这里要注意一点,要设置 HTTP Header 以便让 iOS 设备明白这个是一个可以安装的 app.Code 如下

//set plist and ipa path
//set public as the static resource and view template
app.use(express.static(__dirname + "/public"));
app.set("views", __dirname + "/public");
app.engine("html", require("ejs").renderFile);
//set plist and ipa path
const config = require("./config.js");
const appPath = "/app/" + config.APP_NAME + ".ipa";
const plistFilePath = path.join(__dirname, "/app/manifest.plist");
const ipaFilePath = path.join(__dirname, appPath);

app.get("/", function (req, res) {
  const downloadUrl =
    "window.location.href='itms-services://?action=download-manifest&url=" +
    config.WEB_URL +
    "/app/download'";
  res.render("app.html", { downloadUrl: downloadUrl });
});

//response to download action
app.get("/app/download", function (req, res) {
  res.set("Content-Type", "text/xml plist");
  res.sendFile(plistFilePath);
});
//Set HTTP Header and transfer app stream
app.get(appPath, function (req, res) {
  res.set("Content-Type", "application/octet-stream ipa");
  res.sendFile(ipaFilePath);
});
//Set HTTP Header and transfer app stream
app.get(appPath, function (req, res) {
  res.set("Content-Type", "application/octet-stream ipa");
  res.sendFile(ipaFilePath);
});

public/app.html

这里是网站的主 html,我用了 ejs 来嵌入 config.js 里面的 web 的 URL

完成了这些网站就基本大功告成

Step 3 - 网站部署到 Bluemix

这一步可以让网站让每个人都访问到,可选的云服务蛮多的。Amazon, Azure, Heroku 都不错。为了部署快捷我还是比较倾向于 PaaS 服务,而且 IBM 还有免费的 Account 给员工,何尝不利用下呢。 哼,连免费的水果都木有,当然要多想别的方法薅羊毛了^_^

首先在 bluemix 新建一个 app,选择 Node.js SDK

image

下载 Starter Code, 用里面的 mainfest.yml 把 Sample Code 的替换掉,当然你也可以手动更改 Sample Code

applications:
  - path: .
    memory: 256M
    instances: 1
    domain: au-syd.mybluemix.net
    name: sample-ios-distribution
    host: sample-ios-distribution
    disk_quota: 1024M

然后跟着 Bluemix 的 Get Started, cf push!

image

最后能看到成功部署的信息

image

使用实例

可以用 iPhone 或者 iPad 来直接访问网站

image

然后点击下载按钮,可以看到安装提示

image

在桌面可以看到 app 正在安装

image

安装完成后需要去 Setting->信任一下开发者就完成了,毕竟不是从亲儿子 Appstore 上下的。

image


Me

I am CTO @ Airsquire. I am living in Netherlands