# 自动更新API

考虑到大多数 iFLYOS 设备也有更新设备能力的需求,我们也提供了在线更新 (OTA) 服务。借助在线更新平台,你可以向你的 iFLYOS 硬件分发新的固件。

# Android 实现

介绍

我们提供了 Android 端的 OTA 参考实现源码,演示了如何调用 RESTful 的调用方式和更新判断逻辑。厂商可以根据源码进行二次开发。

# 开发环境要求

  • Git
  • Android Studio 3.1.2 或以上
  • 能够正常访问 jCenter、Google Maven 的网络连接
  • 一部 Android 5.1 或以上的开发设备(或以平板电脑代替)

# 下载源码

git clone https://github.com/iFLYOS-OPEN/OTAClient-Android

使用 Android Studio 打开同步下来的 OTAClient-Android 工程。首次打开需要等待 Gradle 联网下载一些依赖库,可能需要较长时间,需要保持网络畅通。

# 集成提示

OTA 通常需要和设备的 Android 系统紧密结合,需要进行一些简单的定制。下面将向你讲解。

# 1. 填入 Client ID 和 OTA Secret

打开 app/build.gradle (opens new window),在 IFLYOS_CLIENT_IDIFLYOS_OTA_SECRET 两个常量定义内填入你的 Client ID 和 OTA Secret。

buildConfigField "String", "IFLYOS_CLIENT_ID", '"**********"'
buildConfigField "String", "IFLYOS_OTA_SECRET", '"***********"'

# 2. 接入 Device ID 获取方式

默认实现通过 cn.iflyos.open.ota.DeviceId (opens new window) 类获取设备的唯一 Device ID。如果你的设备使用了其它的 Device ID 获取方式,你需要将这个类改为你的设备所使用的获取方式。

package cn.iflyos.open.ota;

public class DeviceId {

    // TODO: 厂商应该根据自己设备重新实现这个方法
    public static String get() {
        return /* ..... */;
    }

}

# 3. 调起 OTA 服务

考虑到一些设备的 Android 有自己定制的自启动方式,这个 OTA 程序没有实现自启动。你可能需要自己实现一个 BOOT_COMPLETED 监听器唤起 OTA 服务,或从你的设备的其它地方调起 OTA 服务。

通常情况下,如果你需要从其它应用调起 OTA 服务,你需要在 AndroidManifest.xml 里将 UpdaterService 标记为 android:exported="true",并通过 startService() 调起 OTA 服务:

Intent intent = new Intent();
intent.setClassName(
        "cn.iflyos.open.ota",
        "cn.iflyos.open.ota.UpdaterService");
startService(intent);

# 4. 赋予系统权限

由于 Android 中只有系统应用才拥有安装或更新应用的权限,因此你需要将编译的 APK 放到 /system/priv-app 目录下才能顺利执行更新。

# RESTful API

# API 地址

https://ota.iflyos.cn

# 认证

为了确保你的固件更新包不被其它设备非法获取,OTA 接口的所有请求需要经过这个项目的 Client ID 和 OTA Secret 的签名认证。

具体来说,所有 API 请求需要加入以下 HTTP 头:

  • X-Client-ID - 该项目的 Client ID
  • X-Device-ID - 设备唯一的 Device ID,用于推送灰度更新
  • X-Timestamp - 当前的 UNIX 时间戳(秒)
  • X-Nonce - 每次请求随机生成的字符串
  • X-Signature - 根据以上信息计算的签名。

其中,X-Signature 的计算方式是,依次将 X-Client-IDX-Device-IDX-TimestampX-Nonce 以及你的 OTA Secret 以冒号 : 连接,计算所得的字符串的 SHA-1 哈希值。伪代码表示如下:

SIGNATURE = sha1("${CLIENT_ID}:${DEVICE_ID}:${TIMESTAMP}:${NONCE}:${SECRET}")

# 取得 OTA 固件列表

GET /ota/client/packages HTTP/1.1
Accept: application/json
X-Client-ID: ***
X-Device-ID: ***
X-Timestamp: ***
X-Nonce: ***
X-Signature: ***
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": 4,
    "revision": 20,
    "url": "https://xxxxxxxxx"
  }
]
  • id 本次更新包的 ID,下面需要用到
  • revision 固件版本
  • url 固件下载地址

设备应当在本地记录当前已安装的固件的 revision。每次取得固件列表之后,将接口中的 revision 与本地比较,如果接口数据比本地新,则通过 url 下载安装。安装完毕后通过下述 PUT 接口将刚刚安装完成的 id 反馈给 OTA 平台。

# 上报 OTA 结果

PUT /ota/client/packages HTTP/1.1
Content-Type: application/json
X-Client-ID: ***
X-Device-ID: ***
X-Timestamp: ***
X-Nonce: ***
X-Signature: ***

{
  "pids": [4]
}
  • pids 当前已安装的更新包的 ID