小米路由器插件开发文档
sdk level 5 新增功能
- c++ sdk 中增加了批量下载功能
- c++ sdk 中添加获取下载列表功能
- c++ sdk 添加下载到用户数据盘的功能
- c++ sdk 中添加文件变化通知功能
- http api 中添加批量下载 api
- http api 下载任务时可以指定相对用户数据盘的相对路径作为下载目录
- http api 中添加运行命令 api
- http api 获取idforvendor
- 脚本 sdk 中添加 plugin_action 命令
- 脚本 sdk 中添加 plugin_download 命令
sdk level 4 新增功能
- sdk 中 Plugin 类添加向小强 app 发送 feed 的功能
- sdk 中 DeviceManager 类添加设置上网权限的功能
- sdk 中 DeviceManager 类添加获取路由器信息的功能
- http core api 中添加设置上网权限的功能
- http core api 中添加获取路由器信息的功能
1. 概述
小米路由器插件(以下简称“插件”)是对小米路由器本身进行扩展,能够完成很多有用和有趣的功能。
插件包含两部分:
- 供远程调用的web控制页(必须)
- 在路由器中运行的程序(可选)
当一个插件安装好之后,用户可以从手机上打开插件,看到一个展示的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下载打包工具
-
Linux 打包工具使用方法: 下载前需要安装的库: sudo apt-get install openssl sudo apt-get install libzip-dev 下载打包工具(www1.miwifi.com/miwifi_open.html): http://bigota.miwifi.com/xiaoqiang/sdk/tools/sdk_package.zip 解压后会得到64位打包工具,plugin_packager_x64和32位打包工具 plugin_packager_x86,还有xiaomi.project文件。根据提示开发者自己编辑xiaomi.project文件,然后运行plugin_package,plugin_packager 会读入xiaomi.project文件(xiaomi.project文件下文会详细介绍,详见 2.6),并且根据 xiaomi.project 文件的配置信息生成 app.mpk(windows下是appSigned.mpk)文件,这个文件就是需要上传服务器的签名后的压缩包。
-
Windows 打包工具的使用方法: key和证书申请文件的生成脚本,运行gencsr.bat可以生成key和csr文件,key是私钥,csr文件是开发者证书申请文件,利用csr文件在 dev.xiaomi.com上换回pem文件。 http://bigota.miwifi.com/xiaoqiang/sdk/tools/csrgen.zip 打包工具,用户填入所有的信息并选择key和pem文件,就会自动生成 mpk。 http://bigota.miwifi.com/xiaoqiang/sdk/tools/windows/packagetool.1.2.zip 工具依赖于.Net4.5安装包:http://bigota.miwifi.com/xiaoqiang/sdk/tools/NDP451-KB2858728-x86-x64-AllOS-ENU.zip windows打包工具截图如下:
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号:
- /api-third-party/service/datacenter/download_file 下载一个指定的Url到路由器
打包插件: 打包插件的流程,先填写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就能在路由器文件管理的下载目录里看到啦。
卸载插件: 在手机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 |
---|---|
参数 | 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 任务id的list |
作用 | 暂停下载任务 |
SDK level | 2 |
5.启动下载任务
接口 | DownloadResult ResumeDownloadItems(const std::vector |
---|---|
参数 | itemIds 任务id的list |
作用 | 启动已暂停的下载任务 |
SDK level | 2 |
6.删除下载任务
接口 | DownloadResult DeleteDownloadItems(const std::vector |
---|---|
参数 | itemIds 任务id的list |
作用 | 删除下载任务 |
SDK level | 2 |
7.获取下载任务列表
接口 | Code GetDownloadList( std::vector |
---|---|
参数 | 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:设备信息 |
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参数,这个用来标示路由器 |