Skip to content

06 常见问题

chengww edited this page Dec 5, 2022 · 24 revisions

常见问题

我们收集了诸多开发者关心的问题。在遇到问题时可以在此页面搜索一下关键字看看有没有自己关心的问题,此文档保持高频更新,更多问题请大家在后台提工单。

根据我们后台收到的工单情况统计来看,大多数开发者遇到的问题都是旧版APP上才有的,很多问题其实已经在新版APP上解决了,所以请各位开发者,在提工单之前务必前往firim上更新一下APP,看看BUG是否已经解决,以免不必要的麻烦。Android下载地址iOS下载地址 下载密码:keliyuan

高频问题置顶

1、我的设备是否开发米家扩展程序?

请仔细阅读小米IoT开发者网站中的开发引导。我们目前支持 WiFi、BLE、ZigBee(需要网关)通讯的智能设备,NB 目前正在内测,不支持传统经典蓝牙设备。无论何种通讯方式,请尽量适配小米IoT协议,可快速开发,自有协议设备接入请联系我们。米家扩展程序暂时不支持p2p的视频播放,具有这类功能的设备如摄像头,接入请联系米家工作人员,采用其他方式。

2、米家扩展程序是否允许访问自己的后台服务器?

禁止直接访问自己的网络服务,需要进行后台对接,否则无法通过审核,详情请咨询米家后台工作人员。

3、蓝牙设备的固件升级(OTA),扩展程序如何处理?

扩展程序使用 js 语言,利用SDK提供的蓝牙读写接口实现,直接OTA。

4、后台API返回的错误码

米家 App 的云端 API 返回已知错误码:

0 OK
-1 没有权限
-2 设备离线
-3 超时
-4 服务器错误
-5 设备错误
-6 无效的请求,这个情况比较多,需要日志详查
-7 未知的设备id
-8 参数错误,某个参数未设置或设置不对
-9 未知错误
-11 重复请求
-12 请求太频繁,常见合作公司压测接口时返回
-13 常见于独立app验证,遇到此错误多是6000权限没有通过或scope设置问题
-17 尚未收到返回结果,多见于异步调用
-21 语音控制session过期
-22 分享设备数量超过限制

其余错误码请详询后台工作人员

5、为什么我的设备又打不开了,提示: 1.请升级APP至最新版本 2.提示model不支持

检查:

  1. 检查账号是否在产品白名单,换一个确认是白名单的账号试试,若还是不行,进行下一步

  2. 抓包fetch_plugin接口,看是否有数据返回,若有,则可以提bug了。若没有,进行下一步

  3. 检查资源包的asset_level,看看代码中的asset_level和资源包中的asset_level是否一致。如果不一致,请更新代码重新打包。若一致,进行下一步

  4. 让对接此款设备的产品,去support后台(http://support.io.mi.srv/new/page/develop/plugin.html#/) 检查设备的插件状态和是否有资源包,如果是合作开发,修改插件状态为未上线。如果用到了资源包,是否有资源包修改为是。如果是RN插件,修改插件状态为白名单测试 ,是否有资源包状态为否。清除缓存,等10分钟之后,如果还没法打开,报bug

6、为什么我的设备无法快连: 1.提示“请升级APP至最新版本” 2.点击无响应点不动 3.提示model不支持

检查:

  1. 检查账号是否在产品白名单,换一个确认是白名单的账号试试,若还是不行,进行下一步

  2. 让对接此款设备的产品,去support后台(http://support.io.mi.srv/new/page/develop/plugin.html#/) 检查设备的快连状态,是否为白名单状态,若不是,改为白名单状态。若是,下一步

  3. 检查代码中是否有registerDeviceModelId,如果不是,请注册model。如果是,请提issue,报bug。

7、设备初始化失败(code)

0 设备不存在
1 设备model不对
2 插件信息下载失败
3 插件包下载失败
4 插件包错误
5 插件包地址错误
6 成功
7 云端未拉到配置信息(非插件),但本地代码声明要求资源包

8、已加入白名单但是快连入口无法添加设备/设备列表无法看到设备

  1. 确认登录的是 大陆服务器,现阶段并不支持海外服务器的白名单调试。有此需求请联系刘军
  2. 清除缓存,等待10分钟左右登录重试

9、设备属性订阅及消息推送问题(仅供Android参考)

  • 相关代码
// 订阅
Device.getDeviceWifi().subscribeMessages
// 监听回调
DeviceEvent.deviceReceivedMessages.addListener

在进行设备属性订阅时,通常编写好代码运行后,可能遇到当设备属性发生改变时,代码却没有触发监听回调,造成这种问题可能有多方面原因,例如设备端没有上报给服务端或服务端没有push消息到移动端或移动端APP没有发送消息到扩展程序框架等等,下面主要讲解下移动端(Android)的排查方法,具体如下:

第一步:排查是否订阅成功

// 在执行这行代码的时候,如果订阅成功, 会输出一行log日志
Device.getDeviceWifi().subscribeMessages

// log日志例如如下, logcat 可以通过 miot-rn-plugin 关键字过滤log日志
I/miot-rn-plugin:    subscribeEvent : onSuccess3F2266876C6738F2AE1BC1B255F958A5

如果没有打印log日志,请查看插件中的订阅相关js代码是否有问题或subscribeMessages是否返回了错误信息。

第二步:排查监听代码是否执行

// 监听代码如下,建议该代码放在componentWillMount 中执行
DeviceEvent.deviceReceivedMessages.addListener

如果此处代码未执行,当然插件无法收到原生层发送到js的事件。

第三步:查看log日志,排查扩展程序框架层是否收到push消息

// 如果框架层收到push消息,会打印如下log日志
I/miot-rn-plugin: eventName: deviceRecievedMessages_36621  action: devicestatuschanged 
			data: { NativeMap: {"data":"[{\"key\":\"prop.on\",\"time\":1565766277,\"value\":[true]}]",
				  "did":"92361471","eventName":"deviceRecievedMessages_36621",
				  "subcribeId":"3F2266876C6738F2AE1BC1B255F958A5"} }

如果未发现log日志,请转到第四部再次排查;

第四步:查看log日志,排查米家APP是否收到push消息

// 如果米家APP收到push消息,会打印如下log日志, 可以通过 DevicePushMsg 关键字过滤log日志
I/DevicePushMsg: onReceiveMessage--> messageId: b1097c08fc7570e89586ae9c1393a275A14F4907369304DCAEC24D8B74783F93    
				messageBody: {"attrs":[{"key":"prop.on","time":1565767653,"value":  
                                               [false]}],"did":"92361471",
					       "model":"xxx.xxx.xxx","subid":"3F2266876C6738F2AE1BC1B255F958A5"}

如为发现log日志,请继续第五步进行排查;

第五步:查看log日志,排查 push service是否收到服务端下发的消息

该步骤,请使用 PushManager 来 过滤日志来查看,查看具体的log信息。

{
"body":{
    "attrs":[{
    "key":"prop.2.6","time":1565856313,"value":[41]}],
    "did":"126664235","model":"xxx.xxx.xxx","subid":"1guaRvHtSBSum4EzMmh1Yw"},
"msgid":"565095fe4b8e417f4cc908b26b4365a71guaRvHtSBSum4EzMmh1Yw",
"type":"device"}

重点看下消息 type值,通过如上方法订阅的,只能收到"type":"device" 的消息类型。

第六步:排查pushservice服务是否启动

// 手机通过USB连接好电脑,cmd 输入如下一行命令
adb shell ps | adb shell grep com.xiaomi.smarthome

通过如上一行命令,可以查看 米家APP的进程信息,如下图:

对于小米系列手机,通常不会有 pushservice 进程 ,该步骤排查可以忽略,非小米系列手机,应该会有pushservice 这个进程,如果没有,请杀掉米家APP再次打开,通过cmd再次输入如上命令,查看是否有pushservice这个进程,如果仍然没有,请反馈给米家。(存在部分小众手机生产商会自动杀掉pushservice 进程)。

注意:遇到此问题,请按照如上步骤排查问题,如仍然未解决,可以提issue或工单,同时请说明哪一步骤出现问题并提供log日志,方便我们及时排查, 同时还需提供给uid/did、时间、期待收到的属性/事件信息,方便服务端同学进行排查。

其他:

  • 一次属性变化,收到多条push消息

    请通过log日志查看,每条log日志中subcribeId 或 subid 对应的值是否相同,如果不同,请排查插件代码是否进行过多次订阅,如果相同,请继续查看log中time的值是否相同,如果相处较大,可能是服务端某种原因,导致两个不同的消息同时发送到米家APP。

10、callMethod 超时等问题

关于callMethod的新旧框架差异性问题

老框架下使用方法:
// 文档说明
MHPluginSDK.callMethod(method, params, extraInfo, (res, json) => {});

// 只有params的example
MHPluginSDK.callMethod("get_config_version", ["audio"], {}, (res, json) => {});

// 只有extraInfo的example
var params = { "operation": "query", "req_type": "alarm", "index": 0 };
MHPluginSDK.callMethod("alarm_ops", [], { "params": params }, (res, json) => {});
// 由于历史原因,extraInfo必须是params为key的json,里面包含真正的payload数据。
新框架下使用方法:
// 文档说明
Device.getDeviceWifi()
  .callMethod(method, params) // 新框架将params和extraInfo整合为一个参数
  .then(res => {//here is the success result})
  .catch(err => {//error happened})

// 相应的新写法
Device.getDeviceWifi()
  .callMethod("get_config_version", ["audio"])
  .then(json => {})
  .catch(res => {})

let params = { "operation": "query", "req_type": "alarm", "index": 0 };
Device.getDeviceWifi()
  .callMethod("alarm_ops", params) // 这里是主要变化,直接传入真正的payload
  .then(json => {})
  .catch(res => {})
callMethod方法的保护:

为了防止频繁调用rpc指令给服务器造成压力,callMethod底层做了保护机制。对于相同接口两次调用时间interval最好超过1500ms,不然大概率报错。附上实验测试结果(未进行大量实验)仅供参考。表格内容表示报错比率。

interval(ms) 250 500 1000 2000 5000
MHPluginSDK.callMethod 406/540 202/400 55/457 16/300 0/100
Device.getDeviceWifi.callMethod 409/540 255/500 24/441 4/300 2/100

interval < 2000,大概率报错:callMethod failedError Domain=MiHomeNetworkErrorLocal Code=-12 "(null)",请尽量避免。

interval >= 2000,极小概率报错:callMethod failedError … error={↵ code = "-3";↵ message = timeout;↵}}",属于正常现象。

11、 miot-spec属性获取或者设置失败的问题,报code -704090001之类的错误

请参考 文档里面的 状态码 部分。

12、设备连接和扩展程序调试

开发扩展程序是否支持使用 iOS|Android 模拟器?

支持Android模拟器,不支持iOS模拟器,由于要使用 AppStore 版的米家App进行调试,无法在模拟器上运行。

13、为什么我使用 Android 客户端已经绑定了的设备,在iOS的设备列表里却看不到?

请联系开发人员将你的产品 model 状态设置为白名单可见。同一个产品,Android 和 iOS 的设置是分开的。

SDK 和 React Native

本地调试时,为什么有时文件明明做了改动(包括添加、修改、删除图片等),但刷新扩展程序却没有发生变化?

npm 有缓存,遇到这种情况,请按照如下各种操作试试:

  1. 刷新扩展程序
  2. 使用 npm start --reset-cache 清空重启服务器并清空缓存
  3. 彻底关闭 terminal 并重新打开
  4. 重启电脑

SDK npm install失败

1、切换淘宝镜像 npm config set registry http://registry.npm.taobao.org 再执行npm install

2、使用科学上网的方式

3、手动下载我们已经安装好了的node_modules文件

名称:node_modules.zip 地址:https://kpan.mioffice.cn/webfolder/ext/v8VeKZfkId4%40?n=0.7158690276978581 密码:2a62

14、怎样判断设备离线

云端服务器一段时间内收不到设备的心跳包,即判定设备离线。扩展程序中可以使用DeviceEvent.deviceStatusChanged.addListener的方式来监听设备的在线/离线状态通知

15、页面切换动画怎样取消

参见react native github

16、页面怎样切换横竖屏?

  1. 使用react-native-orientation库处理转屏,参见转屏demo扩展程序
  2. 需要横竖屏切换的页面需要Modal容器作为最顶层视图
  3. 退出具有横竖屏操作的页面前请还原横竖屏设置为竖屏:Orientation.lockToPortrait()

17、米家app提示需要进行版本升级

对于Android版米家app,首页设备列表页面点击某一设备会提示:版本过低部分功能无法使用,但是已升级到最新版本。

通常是新设备可能会出现这样的提示,原因是米家APP获取不到设备对应的插件包信息,排查方法如下:

步骤1:确定是否为新设备?

如果是新设备,请转向步骤2,如果是旧设备,请转向步骤3。

步骤2:是否有上传插件(RN为mpkg文件)到扩展程序平台?并且设备是否与某一扩展程序有绑定关系?

对于首次开发扩展程序的开发者可能不理解如上问题,请查看 开发简介-上传发布。 如果没有上传过插件,需要上传一个插件包(即便是一个空的插件包也可以,打包发布,不需要上线),上传插件后,可能存在米家APP无法立刻下载到对应的插件,需要等待半小时之后再进行测试。

步骤3:抓包查看网络请求

米家首页点击某一设备的时候,会发起plugin/fetch_plugin 这样的网络请求,获取插件包信息,返回的数据中查看下latest_info下的download_url是否有信息,如果没有,确实又有上传过插件包并且与设备有进行绑定关系,请提工单,同时附上抓包信息。

18、米家app进入插件无法加载到最新插件包

开发者在对插件包(mpkg文件)上传到开发者平台打包发布后,米家app无法加载到最新的插件包或出现加载新旧包轮换(即不稳定)的现象。

排查方法如下:

1)对于出现加载新旧包轮换(即不稳定)的现象

通常都是白名单账号出现这种问题,出现这种问题的原因是服务端对数据需要进行同步,同步需要时间,通常上传发布插件包等待半小时后基本不会复现。对于线上非白名单用户是不会出现这种情况的。

2)对于米家APP无法加载到最新插件包的问题

原因可能有以下几点:

1、米家app版本过低,无法下载到最新的插件包,请及时到fir上更新米家app;

2、在米家首页点击某一设备的时候,会发起plugin/fetch_plugin 这样的网络请求,获取插件包信息,返回的数据中查看下latest_info下的download_url的信息,手动通过浏览器输入download_url下载插件包查看下是否为您上传的最新插件包。发起的请求有一个api_version, 看是否大于等于您插件包依赖的sdk版本,如果小于则需要更新apk。

米家APP版本与扩展程序SDK版本的关系:在firim上的安装包下更新日志一栏有写此版本的APP内置的SDK版本,APP只能拉取到小于等于自身SDK版本的插件,例如:插件是基于10050开发的,然后上传平台打包后,若使用的APP内置的SDK版本号低于了10050,就无法拉取到最新的插件,转而会拉取历史版本中低于10050的那一版本的插件。如果没有低于10050版本的插件,那么就会提示“无法获取插件下载地址”的错误。

以上如未解决,请提工单,并给出抓包信息及您上传的插件包依赖的rn sdk版本。

19.插件连接BLE设备失败

有些时候会出现退出插件,但没有正常断开连接,导致下次打开插件的时候,不能正常建立连接。针对这种情况,通过Device.getBluetoothLE拿到BluetoothDevice对象里面的isConnected返回的虽然是false,但是此时如果尝试调用connect会失败,不过设备会主动断开之前的连接,此时再重试一次就可以connect成功。

20.Android本地调试时,隐私协议等HTML文件显示为源码的问题

可以把自己本地node_modules 文件夹中下的 @react-native-community/cli/build/commands/server/middleware/getSecurityHeadersMiddleware.js 文件中 res.setHeader('X-Content-Type-Options', 'nosniff');注释重新npm start 就可以了。

21.如何抓包

Android抓包教程iOS抓包教程,抓包请务必使用firim上的APP。

22.如何开启/关闭离线弹窗

请开发者在iot后台中,选择“控制台”->“产品”,找到要配置的产品,在“基础配置”一栏,右边选择“产品离线提示”

支持(有提示) 表示设备在离线状态下进入插件时会有半灰色蒙层且除了上面 titleBar部分以外的区域无法响应点击事件,并且会有弹窗提示设备已离线。

支持(无提示) 表示仅有半灰色蒙层且除了上部titleBar部分以外无法点击,不会有弹窗提示。

不支持(无提示) 表示不会有蒙层遮挡也不会有弹窗提示

注意:蓝牙mesh设备即使在首页宫格上显示设备已离线,进入插件后依旧不会有蒙层和弹窗提示。

23.WebView文件访问设置无效

出于安全方面考虑SDK对RNWebview的allowFileAccessFromFileURLs,allowUniversalAccessFromFileURLsallowFileAccess三个API做了限制,默认均为关闭状态,只有指定model的插件才允许设置这三个API,如有需要请提工单。

24.iOS深色模式在切换APP重进后会变成浅色模式

这个是一个RN的bug, 原因是RN退后台瞬间,iOS推送了 light light dark 3次状态,但是由于JS即将退后台休眠,只收到并处理了第一次的light 推送,解决办法是监听到退后台时,插件也停止监听color scheme的变化,实例代码如下

import React from 'react';
import { DarkMode, PackageEvent } from 'miot';
import DynamicColor, { dynamicColor } from 'miot/ui/Style/DynamicColor';
import { dynamicStyleSheet } from 'miot/ui/Style/DynamicStyleSheet';
export default class DarkModeDemo extends React.Component {
  state = {  colorScheme: 'null' }
  myListener = (value) => {
    console.log(`colorScheme from listener: ${ value.colorScheme }`);
    this.setState({ colorScheme: value.colorScheme });
  }
  // 关闭插件所在页面native端的系统强制深色模式(Android)/miot-sdk的反色模式(iOS)
  // 由开发者使用框架提供的接口自己适配插件的深色模式
  UNSAFE_componentWillMount() {  DarkMode.preparePluginOwnDarkMode();  }
  // 退后台时停止监听,回前台继续监听。
  // 退后台后,RN停止工作,将收不到通知。受 iOS 系统影响
  componentDidMount() {
    PackageEvent.packageDidResume.addListener(() => {
      this.addListener()
      // 如果退后台期间改变了  需要刷新
      this.refreshColorScheme()
    });
    PackageEvent.packageWillPause.addListener(() => {
       this.removeListener()
    });
    //查询当前颜色模式
    this.refreshColorScheme()
    // 监听
    this.addListener();
  }
  componentWillUnmount() {
  	this.removeListener()
  }
  refreshColorScheme() {
    const currentScheme = DarkMode.getColorScheme();
    this.setState({ colorScheme: currentScheme });
    console.log('用户是否在iOS端自己适配了深色模式:', DarkMode.darkModeStore.setDarkMode);
    console.log('当前 mode:', DarkMode.getColorScheme()); // rn bug: debug 模式下始终 light  
  }
  // 添加深色模式的监听
  addListener = () => { 
    console.log("添加深色模式监听");
    DarkMode.addChangeListener(this.myListener);
  }
  //取消深色模式的监听
  removeListener = () => {
    console.log("取消深色模式监听");
    DarkMode.removeChangeListener(this.myListener);
  }
  render() {....}
  // 适配整体的 StyleSheet 可以使用 dynamicStyleSheet 函数,其中的色值需要使用使用 DynamicColor 类定义
  const styles = dynamicStyleSheet(....backgroundColor: new DynamicColor('#EEE', '#1A1A1A')  }...);

Android9/iOS上隐私协议深色模式下全黑

这是因为Android9上的WebView无法自动对内容进行反色,但是背景会被反色,所以就形成了黑色背景上展示黑色文字,看起来就是全黑情况。iOS不会对WebView进行反色处理,所以遇到这两种情况需要开发者自己在协议的html文件中适配。 原因可参考:Letting WebView on Android work with prefers-color-scheme: dark

Android9的情况下我们暴露了一个接口DarkModeInterface.needInvertColor()方法供开发者判断,如果返回true表示需要反色,false表示不需要,请开发者根据这个判断设置两个style给文字颜色使用。(仅供Android使用,使用前需判空)

iOS上使用@media prefers-color-scheme dark即可

测试和发布流程

设备重置说明页面如何制作

这个页面是个H5,目前不能自动生成,需要设计师人工审核。如果产品有对应的米家的PM对接,请联系PM。需要提供文案和图片(图片的规格是 1080x1725)。

设备连接页面顶部的产品图片

这个也需要设计师人工审核。需要提供两张图片,尺寸均为 1280x618 ,一张是产品实物图,要求连接指示灯灭。另一张是全透明图,只有对应灯的部分亮,请联系对接的PM或工作人员。(目前也支持提供一个1280x618相同比例的gif)

iOS:从外部navigation返回package未能正确更新 StatusBar 颜色的样式(白色或者黑色)

StatusBar是指 react-native 官方的在手机上显示时间和wifi信号还有电池的那一条Bar 注:该现象未在Android上复现,如果复现,可以提工单反馈。

修复方案 在页面中添加 navigation didFocus listener:


this.didFocusSubscription = this.props.navigation.addListener('didFocus', () => StatusBar.setBarStyle('light-content', true));

Clone this wiki locally