小米路由器插件开发文档

sdk level 5 新增功能

sdk level 4 新增功能


1. 概述

小米路由器插件(以下简称“插件”)是对小米路由器本身进行扩展,能够完成很多有用和有趣的功能。

插件包含两部分:

当一个插件安装好之后,用户可以从手机上打开插件,看到一个展示的web页面。用户通过对web页面进行操作和管理,web处理逻辑会将信息发给路由器,路由器调用开发者的程序或者内置的API进行响应。这样实现了用户与路由器的交互,完成插件功能。

开发者只需要熟悉html,javascript,css 等知识,即可进行资源类插件的开发。

2. 准备

2.1申请路由器应用

开发者需要登录小米开发者中心(http://dev.xiaomi.com/)注册开发者账号,等待审核通过后,得到开发者身份。 然后在“路由器插件”模块中申请“创建路由器插件” 。 创建路由器插件成功后,会获得服务器分配的(AppID,AppKey,AppSecret),用来标识和验证开发者的身份。还会有插件的基本信息,这些基本信息在下文的xiaomi.project 文件里会用到。

2.2开通小米账号接入服务

申请路由器插件之后,在对应的插件应用页面下方有“账号接入服务” 需要启用该服务。 启用该服务的时需要填写回调地址。注意在开放接口里“访问您的小米路由器”的状态是否为“已开启”。 注意, 回调地址要填写开发者实际的前端地址,用户授权后跳转的地址要与这个地址进行验证。否则验证不通过的话会无法访问插件。验证方式是判断这个回调地址是不是授权跳转地址的前缀。 这个回调地址是可以随时更改的。

2.3准备 Web 服务器

插件web资源并不保存在小米的服务器上,所以开发者需要将web资源(html,js,css,image 等)存放到一个外网可访问的Web服务器上。当然,开发者在开发插件的时候,只需要在本地运行一个Web服务器也是可以的。开发者可以使用 httpd,tomcat,IIS 等自己熟悉的Web服务器 。这里简单起见,以node.js为例,在linux环境下搭建一个简单的Web服务器。

首先要在 Linux 上安装 nodejs。

git clone git://github.com/joyent/node.git
cd node
./configure
make
sudo make install

接着写个简单的server.js脚本通过node执行可以作为一个简单的web服务器使用。

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
  }
).listen(80, "127.0.0.1");
console.log('Server running at http://127.0.0.1:80/');

最后保存server.js,在命令行中敲入如下命令。

node server.js

不出问题的话web服务就会正常启动,输出如下。

Server running at http://127.0.0.1:80/

在浏览器里面访问 http://127.0.0.1:80/ ,就会输出 Hello World。 如果出现错误,可能要检查端口是否被占用,以及使用管理员权限运行。

lsof -i :80|grep -v "PID"
kill -9 PID

2.4开发者自己生成公私钥对、证书申请文件

2.4.1使用在线工具

我们在网站(https://d.miwifi.com/plugin/key)上提供了用于生成密钥,证书和插件打包等在线工具。 该工具有个局限是,全部的资源文件不能超过10MB。所以如果插件很大,还是要使用下面的工具。

2.4.2使用linux本地工具

linux环境生成方法如下: a.开发者生成自己的密钥: openssl genrsa -out client.key 1024 chmod 400 client.key (修改权限为仅 root 能访问) openssl rsa -noout -text -in client.key (查看创建的证书)

b.开发者生成自己的证书申请文件: openssl req -new -key client.key -out client.csr (注意:Common Name 填写小米账号id,比如47275757,注意不能填邮箱或者手机号,否则会验证不通过) openssl req -noout -text -in client.csr (查看创建的请求)

c.开发者将证书申请文件交给小米服务器,在dev.xiaomi.com路由器插件模块里面点击“申请开发者证书”按钮。然后服务器会返回一个.pem 格式的证书文件,保存该文件和 a 步骤生成的client.key文件,在 2.5 步骤里面会用到这两个文件。

2.4.3使用windows本地工具

方法参见2.5,生成的证书申请文件,仍需要在dev.xiaomi.com中换回开发者证书。

2.5下载打包工具

2.6xiaomi.project文件的内容

xiaomi.project文件在小米路由器插件的配置文件,插件的基本信息都在xiaomi.project文件里记录。

#请输入插件ID。(即在2.1里面获取到的AppID)
plugin_id= "2882303761517167149";
#请输入插件名称。(即在2.1里面获取到的插件名称)
name= "miroutertest";
#请输入插件介绍。(自定义插件的详细介绍)
introduction= "this is a test plugin introduction";
#请输入插件简介。
summary= "小米路由器插件 test";
#已安装插件图标 URL。(即在2.1里面获取到的已安装插件图标 URL)
installed_icon="http://file.market.xiaomi.com/download/AppStore/594aa36f-4404-4e2c-8e44-ef751ef66c49";
#插件详情图标 URL。(即在2.1里面获取到的插件详情图标 URL)
detail_image="http://file.market.xiaomi.com/download/AppStore/00830c6f-db49-4602-a069-910f88010e2f";
#可安装插件图标 URL。(即在2.1里面获取到的插件可安装插件图标 URL)
market_icon="http://file.market.xiaomi.com/download/AppStore/ffe07b2b-34c4-4dc3-bce4-2a371206d827";
#开发者名称。(即在2.1里面获取到的开发者名称)
developer= "xiaomi";
#请输入插件版本号。(格式:xx.xx.xx,即在2.1里面填写的插件版本号))
version= "1.0.0";
#请输入插件控制页面url。(即在2.2帐号接入服务里面填写的回调地址,该地址必须host在公网上,浏览器或者手机app端就是调用这control_url来控制插件)
control_url= "http://www.xiaomiroutertest.com";
#请输入打包目录。(如果插件没有可执行文件,可不用填写。如果有可执行文件,则将所有可执行文件和start_script放到打包目录下。注意目录结尾必须带/。详情见4.4)
zip_path= "";
#请输入开发者证书文件路径。(即在2.4里面获取到的证书件,.pem 格式)
pem_path= "/home/ltj/build/47275799.pem";
#请输入私钥文件路径。(即在2.4里面获取到的私钥文件,.key格式)
key_path= "/home/ltj/build/47275799.key";
#是否支持R1D
supported_rom= "miwifi_rom 或者 miwifi_rom_mini";
#是否需要访问公共存储目录
access_userdata= "true";
#是否需要支持"下载"功能,此项为true才能够使用下载相关的sdk
support_download= "true";
#是否需要支持"vpn 操作",此项为true才能够使用vpn相关的sdk
support_vpn_operation= "true";
#是否需要支持"已连接的设备信息",此项为true才能够使用链接设备信息相关的 sdk
support_connected_device_info= "true"
#是否需要支持"访问U盘",此项为true才能够使用访问U盘相关的sdk。并在插件跟目录出现extdisks文件夹。
support_usb_disk_mount= "true"
#是否需要支持"文件变化通知"
support_notify_file_changed = "true"
#Sdk level 是描述路由器rom提供的api能力的。如果插件用到了高level的api,那么该插件只能在高于此level的rom上运行。
sdk_level = 3

2.7 本地安装插件

生成好了mpk文件(也就是插件安装包文件),那怎么在路由器里安装呢?这里需要先将mpk文件放到手机里,然后用小米路由器手机客户端上传该mpk文件到路由器里面,具体的UI入口在2.0App“工具箱”里面,右上角有个menu,点击后会提示上传插件并安装,安装完毕后在已安装插件里面就能看到自己的插件啦。(这里需要注意上文说的control_url一定要在公网上否则手机app的webview 控件会无法访问control_url)

3.开发

这里举一个插件的例子,插件的功能是下载一个url到路由器里面。开发平台是Ubuntu 64bit。 先写一个 server.js,具体内容如下:

var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs"),
rootDir = "/home/test/www/"; // 这里 rootDir 修改成自己的目录
http.createServer(function (req, res) {
    var pathname=rootDir+url.parse(req.url).pathname;
    if (path.extname(pathname)=="") {
        pathname+="/";
    }
    if (pathname.charAt(pathname.length-1)=="/"){
        pathname+="index.html";
    }
    console.log(fs);
    path.exists(pathname,function(exists){
        if(exists){
            switch(path.extname(pathname)){
                case ".html":
                    res.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
                    break;
                case ".js":
                    res.writeHead(200, {"Content-Type": "text/javascript"});
                    break;
                case ".css":
                    res.writeHead(200, {"Content-Type": "text/css"});
                    break;
                case ".gif":
                    res.writeHead(200, {"Content-Type": "image/gif"});
                    break;
                case ".jpg":
                    res.writeHead(200, {"Content-Type": "image/jpeg"});
                    break;
                case ".png":
                     res.writeHead(200, {"Content-Type": "image/png"});
                     break;
                default:
                     res.writeHead(200, {"Content-Type":"application/octet-stream"});
}
           fs.readFile(pathname,function(err,data){
res.end(data);
});
    } else {
        res.writeHead(404, {"Content-Type": "text/html"});
        res.end("<h1>404 Not Found</h1>");
        }
        });
}).listen(80, "127.0.0.1");
console.log("Server running at http://127.0.0.1:8 /");

执行 sudo node server.js Server running at http://127.0.0.1:80/ 如果出现错误请看 2.3 去小米开发者中心执行 2.1 和 2.2, 获取到 appID, 接入小米帐号服务

Oauth 的说明: 用户在第一次使用插件时,插件会跳转到授权页面,引导用户授权插件使用自己的设备;授权成功之后,插件拿到access token,进而调用服务器的 API 去执行一些操作,完成插件的功能。其中的具体流程有些复杂的,遵循OAuth2.0标准,详情参见http://dev.xiaomi.com 的开发文档。为了简化开发,我们将上述流程简单封装成一个javascript 的 API。下面的开发说明就是基于这个 API 进行的。

绑定 host(方便本地调试用): 还记得我们在2.2步骤里面在小米开发者中心填写的回调地址吗,假设为http://www.xiaomiroutertest.com/, 那么开发者需要将 127.0.0.1 绑定到 www.xiaomiroutertest.com 。

Linux 环境下执行: sudo vim /etc/hosts 输入一行 127.0.0.1 www.xiaomiroutertest.com 保存后退出 Windows 环境下以管理员权限在 C:\Windows\System32\Drivers\etc\hosts 文件 添加 127.0.0.1 www.xiaomiroutertest.com

完成基本 UI 代码: 在/home/test/www目录下,我们新建一个文件夹sample/download。在文件夹内 , 新建index.html文件。输入下面内容代码。 在head标签中,我们引用了router_request.js,里面包含了我们封装的API使用方法。因为是依赖jquery的 , 所以必须也要引用jquery.js,版本使用1.9.0以上即可。

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <script src="http://code.hs-cn.com/jquery/jquery-1.7.1.min.js"></script>
  <script src="http://app.miwifi.com/js/router_request.js"></script>
  <title>插件Sample-下载一个URL到路由器</title>
</head>
<body>
  <h1>插件Sample-下载一个URL到路由器</h1>
  <table id="device_table">
    <tr>
      <td>输入路由器ID</td>
      <td>
        <input type="text" id="deviceIdText" placeholder="路由器ID">
      </td>
    </tr>
    <tr>
      <td>输入要下载的URL</td>
      <td>
        <input type="text" id="urlText" placeholder="资源url">
      </td>
    </tr>
    <tr>
      <td>操作</td>
      <td>
        <input type="button" value="授权" id="authorizeButton">
        <input type="button" value="下载" id="downloadButton">
      </td>
  </table>
</body>
<html>

这里 http://app.miwifi.com/js/router_request.js ,我们可以在外网上访问,我们已经把它封装成一个api 。 打开 http://www.xiaomiroutertest.com/sample/download/index.html 将会得到下面的页面。 (如果看不到内容,请按ctrl+F5,强制刷新,注意ctrl+F5和直接F5的区别 ) 插件打开页面

插件授权 : 当用户点击“授权”的时候,如果用户未进行授权过,则跳转到授权页面。当用户同意后,自动跳转回来。 如果尚未得到用户授权,那么就请求用户授权。通routerRequest.hasAccessToken()判断插件是否已经拿到用户的授权,如果没有就使用routerRequest.authorize(directUrl, appId)方法,跳转到小米用户授权页面,显式的让用户授权给appId对应插件。授权完毕之后,会自动跳转到directUrl指定的url来。 必须保证小米开发者中心“账号接入服务”中填写的回调地址是这个directUrl的前缀。

if (!routerRequest.hasAccessToken())
    routerRequest.authorize(window.location.href, appId);
}

向服务器发起API请求: 当用户填写好正确的路由器ID和下载的URL之后,点击”下载“的时候,我们将使用routerRequest.request方法完成这个任务。下面逐一讲解各个参数的意义。

    routerRequest.request({
      path: "/api-third-party/service/datacenter/download_file",
      type: "GET",
      data: {
        deviceId: deviceId, // 这个参数只是调试时添加,上线后要去掉。
        url:url,
        appId: appId,
      },
      success: function(data) {
        var response = jQuery.parseJSON(data);
        if (response.code != 0) {
          console("error:", data);
          return;
        }
        console.log("success");
      },
      error: function(data) {
        console.log("error:", data);
      }
    });

path:是传入的API请求的路径, 不同API的请求路径是不同的。这里使用的是/api-third-party/service/datacenter/download_file来下载一个URL。

data:是请求的参数。其中,appId是必须要传入的,用来验证开发者的插件的身份;url表示要下载的资源;deviceId表明下载到哪个路由器上,实际开发完插件后,需要去掉,因为插件运行在小米路由器客户端时,客户端会自动加上这个参数的。

success:如果请求成功,会回调success对应的函数。 注意,这里的请求成功不代表操作成功。参数data是一个json 结构,判断data.code是不是0可以知道请求的结果。

error::如果出现授权失败,网络故障等问题会回调error对应的函数。

type: 请求的方法可以是“POST”或者是“GET”, 默认是GET。下面代码中使用的是默认的。

以下是完整的index.html的代码

<!DOCTYPE html>
<html>    
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <script src="http://code.hs-cn.com/jquery/jquery-1.7.1.min.js"></script>
  <script src="http://app.miwifi.com/js/router_request.js"></script>
  <title>插件Sample-下载一个URL到路由器</title>
</head>    
<body>
  <h1>插件Sample-下载一个URL到路由器</h1>
  <table id="device_table">
    <tr>
      <td>输入路由器ID</td>
      <td>
        <input type="text" id="deviceIdText" placeholder="路由器ID">
      </td>
    </tr>
    <tr>
      <td>输入要下载的URL</td>
      <td>
        <input type="text" id="urlText" placeholder="资源url">
      </td>
    </tr>
    <tr>
      <td>操作</td>
      <td>
        <input type="button" value="授权" id="authorizeButton">
        <input type="button" value="下载" id="downloadButton">
      </td>
  </table>
</body>
<script type="text/javascript">
var appId = "2882303761517311469";
$(document).ready(function() {
  $("#authorizeButton").click(function(){
    if (!routerRequest.hasAccessToken()) {
      routerRequest.authorize(window.location.href, appId);
    }
  });

  $("#downloadButton").click(function() {
    var deviceId = $("#deviceIdText").val();
    if (!deviceId) {
      alert("请填写路由器ID");
      return;
    }
    var url = $("#urlText").val();
    if (!url) {
      alert("请填写要下载的url");
      return;
    }
    routerRequest.request({  
      path: "/api-third-party/service/datacenter/download_file",
      type: "GET",
      data: {
        deviceId: deviceId, // 这个参数只是调试时添加,上线后要去掉。
        url:url,
        appId: appId,
      },
      success: function(data) {
        var response = jQuery.parseJSON(data);
        if (response.code != 0) {
          console.log(data);
          alert("错误:" + response.msg);
          return;
        }
        alert("下载url成功");
      },
      error: function(data) {
        console.log("error:", data);
        alert("下载url失败");
      }
    });
  });
});
</script>
</html>

注意: 在路由app里安装了插件后可直接调用HTTP Core Api,在浏览器里调试时需在Api的参数中增加deviceId,开发者可登录http://d.miwifi.com/plugin/deviceList 查看已绑定路由的deviceId,否则调用HTTP Core Api是会提示“数据缺失”。

index.html中,请求下载的时候调用的是path: "/api-third-party/service/datacenter/download_file" 对应的HTTP Core Api是3号:

打包插件: 打包插件的流程,先填写xiaomi.project文件,执行plugin_packager就OK啦。打包完成后就会看到 app.mpk这个文件啦~~ 还可以在网站http://d.miwifi.com/plugin/mipk上填写插件信息,打包下载生成的app.mpk文件。

在路由器上本地安装插件: 在手机app里面可以选择打包好的mpk然后上传安装到路由器里面。

使用插件: 在浏览器里面敲http://www.xiaomiroutertest.com/sample/download/index.html,选好一个设备ID,输入下载的链接,下载成功就会出现下面的情景。下载成功后通过手机app就能在路由器文件管理的下载目录里看到啦。

下载url成功

卸载插件: 在手机1.0app里面,扩展插件里面找到自己安装的插件,右上角有个menu,点击弹出卸载选项。2.0app里的工具箱“添加与管理工具”按钮里点移除插件即可。

上传插件到插件商店: 在dev.xiaomi.com里面对应的路由器插件里面就可以上传刚才打包后的app.mpk啦。

4.开发带有二进制文件的插件

开发者可以开发带有可执行程序的插件,插件的可执行程序在路由器上运行,控制页面可以通过插件系统提供的api进行与可执行文件进行交互。开发者打包时将自己编译好的文件与start_script放在相同目录下,并将该目录传入打包工具,生成mpk包。插件安装时,会将打包目录下的所有文件释放到插件运行的根目录中。

4.1toolchain下载

x64 toolchain下载 下载地址http://bigota.miwifi.com/xiaoqiang/sdk/toolchain/r1d/x64/xiaomi_toolchain.zip

x86 toolchain下载 下载地址http://bigota.miwifi.com/xiaoqiang/sdk/toolchain/r1d/x86/xiaomi_toolchain.zip

4.2lib下载

我们提供了一些基本的库,供开发者使用,包括: boost,curl,json,lbiconfig,libpthread,sqlite3,thrift,openssl 这些库都是现在小米路由器rom中包含的库。开发者可以在代码中使用这些库。 如果还需要其他库可以联系RouterPluginPlatform@xiaomi.com。

lib下载 :

http://bigota.miwifi.com/xiaoqiang/sdk/libs/boost.1.54.0.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/json.0.11.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/libpthread.0.9.33.2.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/sqlite3.3071201.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/curl.7.33.0.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/libconfig.1.4.9.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/openssl.1.0.1h.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/thrift.0.9.1.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/libzip.0.10.1.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/zlib.1.2.7.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/libevent.2.0.19.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/glog.0.3.3.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/gflags.2.1.1.zip

http://bigota.miwifi.com/xiaoqiang/sdk/libs/libiconv.2.4.0.zip

4.3MIWIFI SDK下载和使用

路由器能力的SDK (www1.miwifi.com/miwifi_open.html) http://bigota.miwifi.com/xiaoqiang/sdk/tools/sdk_package.zip http://bigota.miwifi.com/xiaoqiang/sdk/tools/sdk_package_r1c.zip 其中带有SDK 使用sample。

4.3.1MRApp (SDK level 5)

开发者应该写一个类继承自MRApp,并在代码中声明一个派生类的全局变量。这样编译出来的插件从才能正常运行,并带有与插件控制页面交互的功能。例如:

class MyPlugin: public MRApp {
public:
    MyPlugin();
    virtual ~MyPlugin();
    virtual void onLaunched(const std::vector<std::string>& parameters);
 };
 MyPlugin app;

1.onLaunched

onLaunched是插件启动时会被调到的处理函数。

2.onParameterRecieved

onParameterRecieved是控制页面控制插件时会被调到的处理函数。当控制页面中调用http core api 12号,控制插件api时,插件平台会将控制页面传入的信息转发到插件中。然后调用MRApp类的onParameterRecieved函数。插件开发者在onParameterRecieved函数中实现对信息的处理。开发者还可以将处理完毕的信息以函数返回值的形式返回出去,控制页面就可以在12号api中得到返回值。12号api的超时时间为1秒。

3.onExit

onExit是插件退出是会被调到的处理函数,这个函数执行结束后程序就会退出。开发者应该在这个函数中保存相关的数据。

4.onUDiskAdded

onUDiskAdded是当有u盘插入时被调用到的处理函数,参数为U盘的目录。需要在manifest中声明support_usb_disk_mount

5.onUDiskRemoved

onUDiskAdded是当有u盘卸载时被调用到的处理函数,参数为U盘的目录。需要在manifest中声明support_usb_disk_mount

6.onFileSystemChanged(小米路由器mini不支持)

onFileSystemChanged是当磁盘上有文件变化是被调用到的处理函数,参数为U盘的目录。需要在manifest中声明support_notify_file_changed

4.3.2 PluginTools

1.getDeviceId

接口 static string getDeviceId()
参数
作用 开发者可以通过该函数得到当前设备的device id
SDK level 2

2.saveData

接口 static Code savedata(const string& key,const string& value)
参数 key 存储数据用的key,依照这个key来读数据;value 存储数据的内容
作用 开发者可以通过该函数存储一些数据,这些数据可以通过sdk 3号接口和http 5号接口来读取
SDK level 2

3.getData

接口 static Code getData(const string& key,string& value)
参数 key 存储数据用的key,依照这个key来读数据;value 存储数据的内容
作用 开发者可以通过该函数获取一些已存储数据,这些数据是通过sdk 2号接口和http 6号接口设置的
SDK level 2

4.sendPush

接口 ErrorCode::Code sendPush(const std::string & title,const std::string & description)
参数 title 通知的标题;description 通知的内容
作用 该通知会显示在路由器android和iphone客户端
SDK level 4
4.3.3 Downloader

该类中的所有函数需要“下载”权限,插件必须在打包时声明“下载”权限才能使用这些函数。(support_download= "true");

1.新建下载任务(直接下载到用户数据盘)

接口 DownloadResult DownloadToUserData(const std::string& url, const std::string& pathForUserData,bool downloadAgain, const std::string& dupId,string output)
参数 url 要下载的url;pathForUserData 下载到用户数据盘为跟目录的相对目录;downloadAgain 如果是重复下载已有的任务,此参数传true;dupId 如果是重复下载已有的任务,次参数传重复的id;output json格式的结果
作用 用户通过此api可以调用路由器的下载器下载一个文件
SDK level 5

2.批量新建下载任务

接口 Code multiDownload(const std::string& urls, const std::string& pathForUserData,vector& reslut)
参数 urls:以逗号分隔的url;pathForUserData 下载到用户数据盘为跟目录的相对目录;reslut:输出参数,创建任务结果
作用 用户通过此api可以调用路由器的下载器批量下载文件
SDK level 5

3.获取下载进度

接口 DownloadResult GetDownloadProgress(const std::string& id,const bool isHidden = false)
参数 id 要查询的任务id;isHidden 是否是隐藏的下载任务
作用 获取下载任务的进度
SDK level 2

4.暂停下载任务

接口 DownloadResult PauseDownloadItems(const std::vector& itemIds)
参数 itemIds 任务id的list
作用 暂停下载任务
SDK level 2

5.启动下载任务

接口 DownloadResult ResumeDownloadItems(const std::vector& itemIds)
参数 itemIds 任务id的list
作用 启动已暂停的下载任务
SDK level 2

6.删除下载任务

接口 DownloadResult DeleteDownloadItems(const std::vector& itemIds,bool removeFiles)
参数 itemIds 任务id的list
作用 删除下载任务
SDK level 2

7.获取下载任务列表

接口 Code GetDownloadList( std::vector& list)
参数 list 输出参数,下载列表
作用 获取下载任务列表
SDK level 5
4.3.4VpnControllor

该类中的所有函数需要“VPN控制”权限,插件必须在打包时声明“VPN控制”权限才能使用这些函数。(support_vpn_operation= "true" 小米路由器mini不支持)。 1.设置一个vpn设备(proto目前只支持 l2tp)

接口 static ErrorCode::Code createVpn(const VpnInfo& info, string & result)
参数 VpnInfo:要设置的vpn信息;result:输出参数
SDK level 3

2.查看vpn配置信息

接口 static ErrorCode::Code getVpnInfo(const string& name, string & result)
参数 name:vpn名字;result:输出参数{"username":"xiaomi","proto":"l2tp","auto":"0","password":"123","server":"10.237.100.1"}
SDK level 3

3.使用vpn设备拨号

接口 static ErrorCode::Code openVpn(const string& name, string & result)
参数 name: vpn名字;result:输出参数
SDK level 3

4.断开vpn

接口 static ErrorCode::Code closeVpn(const string& name, string & result)
参数 name: vpn名字;result:输出参数
SDK level 3

5.查看vpn拨号状态

接口 static ErrorCode::Code getVpnStatus(const string& name, string & result)
参数 name: vpn名字;result:输出参数{"stat":{"msg":"","code":601},"proto":"l2tp","auto":"0","up":false,"autostart":false,"pending":false,"data":[],"available":true}
SDK level 3

6.注册一个供自己使用的rt _table_name

接口 static ErrorCode::Code registRtTable(const string& tableName, string & result)
参数 tableName: table名字;result:输出参数,大于0表示成功
SDK level 3

7.检查rt _table是否存在

接口 static ErrorCode::Code checkRtTable(const string& tableName, string & result)
参数 tableName:table名字;result:输出参数,返回>0正常,-1 不存在
SDK level 3

8.添加rt_table中的路由条目

接口 static ErrorCode::Code addToRtTable(const string& tableName, const string& port,const string& items, string & result)
参数 tableName:table名字;port:在r1d中,wan口网卡名为eth0.2,vpn设备的dev_name为proto-interface;items:要添加的路由条目,多个用空格分隔;result:输出参数,{"success":2,"fail":0}
SDK level 3

9.删除rt_table中的路由条目

接口 static ErrorCode::Code deleteInRtTable(const string& tableName, const string& port,const string& items, string & result)
参数 tableName:table名字;port:在r1d中,wan口网卡名为eth0.2,vpn设备的dev_name为proto-interface;items:要添加的路由条目,多个用空格分隔;result:输出参数,{"success":2,"fail":0}
SDK level 3

10.清空rt_table中的路由条目

接口 static ErrorCode::Code cleanRtTable(const string& tableName, string & result)
参数 tableName:table名字;result:输出参数
SDK level 3

11.查看rt_table中的路由条目

接口 static ErrorCode::Code getRtTableList(const string& tableName, string & result,int offset=0,int count = 0)
参数 TableName:table名字;offset:起始条目;count:条目数(如果offset和count都是0,则返回前1000条);result:输出参数200.181.112.0/24 dev eth0.2 scope link 220.181.111.0/24 dev eth0.2 scope link
SDK level 3

12.通过源地址使用相应的rt_table ,添加

接口 static ErrorCode::Code addSrc(const string& tableName, const string& items, string & result)
参数 tableName:table名字;items:要添加的路由条目,多个用空格分隔;result:输出参数,{"success":1,"fail":0}
SDK level 3

13.通过源地址使用相应的rt_table ,删除

接口 static ErrorCode::Code deleteSrc(const string& tableName, const string& items, string & result)
参数 tableName:table名字;items:要添加的路由条目,多个用空格分隔;result:输出参数,{"success":1,"fail":0}
SDK level 3

14.查看源地址

接口 static ErrorCode::Code getSrcList(const string& tableName, string & result)
参数 tableName:table名字;result:输出参数192.168.31.2 192.168.31.0/29
SDK level 3

15.修改源地址

接口 static ErrorCode::Code changeSrc(const string& tableName,const string& oldsrc,const string& newsrc, string & result)
参数 tableName:table名字;oldsrc:旧地址;newsrc:新地址;result:输出参数
SDK level 3
4.3.5DeviceManager

该类中的所有函数需要“已连接的设备信息”权限,插件必须在打包时声明“已连接的设备信息”权限才能使用这些函数(support_connected_device_info= "true")。 1.获取链接设备的信息

接口 ErrorCode::Code getConnectedDeviceList(vector & outputList)
参数 outputList:设备信息
SDK level 3

2.设置设备上网权限

接口 ErrorCode::Code setDeviceWanAccess(const std::string& mac, bool enable)
参数 mac:设备的mac地址;enable:是否能链接外网
SDK level 4

3.获取路由器信息

接口 ErrorCode::Code getRouterInfo(RouterInfo& output)
参数 output:输出参数,路由器信息
SDK level 4

4.4编写start_script脚本

start_script是一个由小米路由器定义的用来控制插件行为的一些列命令的集合,开发者可以通过这些命令控制插件的开启,关闭和为安装插件做一些准备工作。提供的命令包括:MKDIR,RUN。 MKDIR命令的作用是在插件安装时创建一个目录。MKDIR后面跟的参数为创建的目录。此命令会在插件安装时运行 RUN命令的作用是运行一个文件。RUN后面跟的参数为插件启动时要执行的文件。此命令会在插件安装、打开插件、路由器启动(如果启动时插件状态是开启)时运行。

例如:

MKDIR /user/
RUN sample -s

开发者将脚本文件写好,命名为“start_script”,放在打包的zip_path根目录下,zip_path参见2.6里面的xiaomi.project文件。

4.5SDK level

Sdk level是描述路由器rom提供的api能力的。如果插件用到了高level的api,那么该插件只能在高于此level的rom上运行。一个插件的sdk level等于该插件用到的sdk和http api中最高的sdk level。例如如果一个插件用到了level为1和2的api,那么该插件的sdk level为2。 每一个路由器rom都有对应的sdk level,rom的level必须大于等于插件的level,插件才能正常运行。

R1D Rom版本 R1C Rom版本 Sdk Level
0.4.58 以上 0.3.1以上 1
0.5.41 以上 0.3.1以上 2
0.6.37 以上 0.3.1以上 3
0.8.19以上 0.5.8以上 4

4.6开发者选项

我们给开发者提供了一个高级功能,见下图。在浏览器访问miwifi.com进入路由管理页面,找到高级功能->开发者选项,输入自己的插件ID ,就可以开通ssh了,在客户端输入ssh plugin@miwifi.com -p 2222就可以登录到路由器里面,然后scp自己的可执行文件到路由器里,就可以在路由器里调试了,比如查看log之类,注意使用scp的时候端口号必须是2222,比如scp -P 2222 a.txt plugin@miwifi.com:/folder1,并且P是大写哦。。需要说明的是,出于安全考虑,我们给插件提供的权限和工具都是有限的,如果有特殊需求请发信联系我们。

4.7 带有可执行文件的插件开发注意事项

插件包中必须要有start_script文件,该文件中必须有至少一个RUN命令用来启动可执行文件。start_script文件需要和可执行文件一起放到mpk包中。

4.8 插件的调试

可以下载gdb进行调试,http://bigota.miwifi.com/xiaoqiang/sdk/tools/gdb.6.8a ,编译程序时加入 -gdwarf-2 -gstrict-dwarf 。

5.可供开发者调用的HTTP Core Api

1.获取设备信息

接口 GET /api-third-party/device
参数 appId: app id
返回 {"code":"0","device":{"id":"","idForVendor":"","name":""}}
SDK level 1

2.批量下载到路由器

接口 POST /api-third-party/service/datacenter/multi_create
参数 appId:app的id;urls:以逗号分隔的url;pathForUserData(optional):下载路径,以用户数据盘为跟目录的路径
返回 {"code":0,"msg":"","list":[{"downloadId":"8","deviceId":"c69ee1b1-037f-4d89-bb38-4d12*"}]} 1.返回值中的downloadId是该下载项目的id,在一个路由器上是唯一的;2.deviceId是路由器的唯一标识,通过deviceId和downloadId可以唯一确定一个文件
SDK level 5
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

3.下载一个指定的Url到路由器

接口 POST /api-third-party/service/datacenter/download_file
参数 appId:app的id;url:下载文件的url;pathForUserData(optional):下载路径,以用户数据盘为跟目录的路径。(sdk level 5);hidden(optional):true,false,表示是否是用户不可见的下载项目,默认为false;downloadName:下载文件的存储名字;tag:自定义标签
返回 {"code":0,"msg":"","downloadId":"8","deviceId": "c69ee1b1-037f-4d89-bb38-4d12*"} 1.返回值中的downloadId是该下载项目的id,在一个路由器上是唯一的;2.deviceId是路由器的唯一标识,通过deviceId和downloadId可以唯一确定一个文件
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }{ "code":2010,"msg":"duplicate url","dupId":"16" }

4.根据id查询下载项目的信息

接口 GET /api-third-party/service/datacenter/download_info
参数 appId:app的id;deviceId:路由器的备份id;downloadId:下载任务id;hidden(optional):true,false,表示是否是用户不可见的下载项目,默认为false
返回 {"code":0, "msg":"", "url": "http://miwifi.com/api-third-party/data/12345/image/1.jpg"} 通过url可以下载downloadId对应的文件
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }{"code":1056, "msg":"invalid device id" } {"code":1057,"msg":"resource is not ready" } {"code":1559,"msg":"datacenter error" }

5.获得app的自定义配置信息

接口 GET /api-third-party/service/datacenter/config_info
参数 appId:app的id;key:配置选项的key
返回 {"code":0,"msg":"","value":"test_value"}
备注 开发者可以通过该函数获取一些已存储数据,这些数据是通过DataTransfer::saveData接口和http 6号接口设置的。
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

6.设置app的自定义配置信息

接口 GET /api-third-party/service/datacenter/set_config
参数 appId:app的id;key:配置选项的key;value:配置选项的value
返回 {"code":0,"msg":"","value":"test_value"}
备注 开发者可以通过该接口存储一些数据,这些数据可以通过DataTransfer::getData()接口和http 5号接口来读取。
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

7.批量获取下载任务信息

接口 GET /api-third-party/service/datacenter/batch_download_info
参数 appId:app的id;ids:需要获取信息的id,以逗号分割,例如"1,3";hidden:true,false,表示是否是用户不可见的下载项目,默认为false
返回 {"code":0,"msg":"","list":[{"id":"1","address":"http:\/\/ww2.sinaimg.cn\/bmiddle\/5823207fjw1e7bzefeaa0j20t62lhqre.jpg", "localFileName":"download1.jpg","type":1,"datacenterErrorCode":0,"downloadSpeed":0,"downloadStatus":1,"fileDownloadedSize":0,"fileTotalSize":195735}{"id":"3","address":"http:\/\/ww2.sinaimg.cn\/bmiddle\/5823207fjw1e7bzefeaa0j20t62lhqre.jpg","localFileName":"download1.jpg","type":1,"downloadStatus":4,"fileTotalSize":195735,"finishedTime":110301310 }]} 参数id:下载任务的Id;address:url;localFileName:文件本地置;type:下载类型(1为链接下载,3为种子下载);downloadSpeed:下载速度;downloadStatus:下载状态(详见下方列表);percent:下载进度;fileDownloadedSize:已下载文件大小(byte);fileTotalSize:文件总大小
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

8.开启插件

接口 GET /api-third-party/service/datacenter/plugin_enable
参数 appId:app的id
返回 { "code": 0, "msg": "" }
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

9.关闭插件

接口 GET /api-third-party/service/datacenter/plugin_disable
参数 appId:app的id
返回 { "code": 0, "msg": "" }
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

10.删除下载任务

接口 GET /api-third-party/service/datacenter/download_delete
参数 idList:用分号分隔开的下载任务ID;deletefile:是否同时删除文件;appId:插件id
返回 { "code": 0, "msg": "" }
SDK level 1
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

11.获取插件开启关闭状态

接口 GET api-third-party/service/datacenter/get_plugin_status
参数 appId:插件id
返回 { "code": 0, "msg": "", "isEnable": false }
SDK level 2
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

12.控制插件

接口 GET /api-third-party/service/datacenter/plugin_control
参数 appId:插件id;info:要传入的信息
返回 { "code": 0, "msg": "" }
SDK level 2
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

13.获取链接设备列表

接口 GET api-third-party/service/datacenter/get_connected_device
参数 appId:插件id;info:要传入的信息
返回 {"mac":"","list":[{"mac":"D7:04","type":"line","company":{"priority":2,"type":{"p":0,"c":0,"n":""},"name":"","icon":""},"ptype":0,"ctype":0,"ip":"","port":0,"name":"B8:CA:3A:A2:D7:04","origin_name":"","online":1,"statistics":{"dev":"b-lan","activets":"10106","onlinets":"34","upload":"116704943","upspeed":"0","ip":"","downspeed":"0","online":"10078","maxdownloadspeed":"4338694","mac":"D7:04","initail":"-567","download":"190415205","maxuploadspeed":"316356","idle":6},"authority":{"wan":1,"pridisk":0,"admin":1,"lan":1},"signal":""}],"code":0}
SDK level 3
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

14.取路由器mac地址

接口 GET api-third-party/service/datacenter/get_router_mac
参数 appId:插件id;info:要传入的信息
返回 {"code":0, "msg":"", result:"aa:aa:aa:aa:aa"}
SDK level 3
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

15.设置设备访问外网权限

接口 GET api-third-party/service/datacenter/set_wan_access
参数 appId:插件id;info:要传入的信息;mac:设备mac地址 ;enable:(bool)是否可以访问外网
返回 {"code":0, "msg":""}
SDK level 4
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

16.获取路由器信息

接口 GET /api-third-party/service/datacenter/get_router_info
参数 appId:插件id
返回 {"code":0,"msg":"","name":"0_cl","version": "0.7.51","type":"R1D"}
SDK level 4
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

17.插件执行命令

接口 GET api-third-party/service/datacenter/run_command
参数 appId:插件id;command:要执行的命令
返回 { "code":0, "msg":"" }
SDK level 5
Error code {"code":1,"msg":"parameter missing"}

18.获取idforvendor

接口 GET api-third-party/service/datacenter/idf
参数 appId:插件id
返回 { "code":0, "idforvendor":"1111" }
SDK level 5
Error code {"code":1,"msg":"parameter missing"}{"code":3,"msg":"Parameter format error" } {"code":5,"msg":"invalid app id" }

附录:downloadStatus列表

Item Value
DownloadStatusNone 0
Downloading 1
DownloadPause 2
DownloadCompleted 4
DownloadStoped 8
DownloadStatusFailed 16
DownloadNotStart 32

6.shell脚本sdk

开发者可以通过一些shell命令来调用路由器的功能(小米路由器mini不支持)。

6.1 plugin_action命令

参数 含义
-s 要求插件在启动和每一次启动新进程时调用该函数,该函数用来记录插件进程的pid,并对这些进程进行管理。如果发现插件没有按照要求记录pid,我们会对该插件进行下架处理。
-p 向路由APP发送通知的内容
-t 向路由APP发送通知的

6.2 plugin_download命令

参数 含义
-a 添加一个新的下载地址
-f 指定下载目录
-l 获取下载列表
-p 根据id暂停任务
-r 根据id启动任务
-d 根据id删除任务

7.错误返回

API常见错误如下

code 描述 解释
96001 client不存在 app ID并未注册,需要检查app ID是否正确
96003 客户端标识符无效 app ID并未启用账号接入服务,所以没有访问用户数据的权限。参见2.2节
96008 token无效或已经过期 权限过期,需要重新授权
96010 重定向URI与预先注册的值不匹配或者不是一个合法的URI 账号接入服务中,填写的回调地址有错误。参见2.2节
3001 没有权限操作 当前登录用户不能操作指定指定路由器
3002 资源不存在 该设备的ID不正确,或者用户与该路由器已经解除绑定关系
3009 数据缺失 大部分情况就是请求参数中缺少deviceId参数,这个用来标示路由器