应用程序小组件是一个微型的应用程序视图,可以嵌入其他应用程序(例如主屏幕)中并接收定期更新。本文档介绍了开发iOS小组件。
创建证书
iOS中小组件(Widget)是一个独立的应用,可以看做是一个独立的App(宿主App的拓展程序),所以我们需要对Widget单独创建证书。
创建Widget
设置Widget和宿主App交互通信
因为Widget的独立性,宿主App要与Widget之间相互通信,需要通过App Group来实现。
生活物联网平台SDK使用指导
下面主要介绍TodayExtension的开发过程,其余Widget开发请参照Apple官方文档自行完成。
设备小组件&场景小组件接口文档和调用过程
设备小组件和场景小组件在开发过程中使用的接口文档(参见场景服务)和调用示例如下。
- 宿主App相关的接口
- 场景小组件
【1】获取已经被添加到小组件的场景list path:/living/appwidget/list version:1.0.0 params:@{} 【2】全量场景查询 path:/living/scene/query version:1.0.1 params = @{@"catalogId": @"0", @"pageNo": @(pageNo), @"pageSize": @(pageSize) } 【3】更新场景小组件 path:/living/appwidget/create version:1.0.0 params = @{@"sceneIds": @[]}
- 设备小组件
【1】获取已经被加到小组件的设备list path:/iotx/ilop/queryComponentProduct version:1.0.0 params:@{} 【2】获取设备的属性列表(目前属性多语言需要入参时传递) path:/iotx/ilop/queryComponentProperty version:1.0.0 params = @{@"productKey":productKey, @"iotId":iotId, @"query":@{@"dataType":@"BOOL”, @"I18Language":@"zh-CN"} } 【3】小组件列表更新 path:/iotx/ilop/updateComponentProduct version:1.0.0 params:更改后的设备list
- 场景小组件
- TodayExtension相关接口
- 场景小组件
【1】获取已经被添加到小组件的场景list path:/living/appwidget/list version:1.0.0 params:@{} 【2】执行场景 path:/scene/fire version:1.0.1 params:@{@"sceneId":sceneId}
- 设备小组件
【1】获取已经被加到小组件的设备list path:/iotx/ilop/queryComponentProduct version:1.0.0 params:@{} 【2】设备小组件,有本地通信和云端通信逻辑,需要集成宿主APP中的长连接绑定 & 订阅,监听长连接正常连接 【3】设备状态变更,需要自行定位/thing/properties 和 /thing/status 的topic,监听状态变更,刷新UI 【4】选中设备,指定ThingShell设置设备属性,通过物的模型,变更属性 【5】如果订阅过Topic,设置【4】成功后,也会受到云端的状态变更通知
- 设备小组件核心参考代码
【1】长连接绑定 & 订阅(相关SDK参见长连接通道SDK) IMSConfiguration * imsconfig = [IMSConfiguration sharedInstance]; LKAEConnectConfig * config = [LKAEConnectConfig new]; config.appKey = imsconfig.appKey; config.authCode = imsconfig.authCode; // 指定长连接服务器地址。 (默认不填,SDK会使用默认的地址及端口。默认为国内华东节点。不要带 "协议://",如果置为空,底层通道会使用默认的地址) config.server = @"" // 开启动态选择Host功能。 (默认 NO,海外环境请设置为 YES。此功能前提为 config.server 不特殊指定。) config.autoSelectChannelHost = NO; [[LKAppExpress sharedInstance]startConnect:config connectListener:self];// self 需要实现 LKAppExpConnectListener 接口 } 【2】注册下行Listener #pragma mark - 注册下行Listener static NSString *const IMSiLopExtensionDidReceiveUpdateAttributeSuccess = @"LAMPPANEL_DIDRECEIVE_UPDATE_ATTRIBUTE_SUCCESS"; static NSString *const IMSiLopExtensionDidReceiveUpdateDeviceStateSuccess = @"LAMPPANEL_DIDRECEIVE_UPDATE_DEVICE_STATE_SUCCESS"; @class TodayViewController; @interface IMSWidgetDeviceListener : NSObject <LKAppExpDownListener> @end @implementation IMSWidgetDeviceListener - (void)onDownstream:(NSString * _Nonnull)topic data:(id _Nullable)data { IMSAppExtensionLogVerbose(@"小组件 onDownstream topic : %@", topic); IMSAppExtensionLogVerbose(@"小组件 onDownstream data : %@", data); NSDictionary * replyDict = nil; if ([data isKindOfClass:[NSString class]]) { NSData * replyData = [data dataUsingEncoding:NSUTF8StringEncoding]; replyDict = [NSJSONSerialization JSONObjectWithData:replyData options:NSJSONReadingMutableLeaves error:nil]; } else if ([data isKindOfClass:[NSDictionary class]]) { replyDict = data; //这里添加云端处理! if (data) { if ([topic isEqualToString:@"/thing/properties"]) { [[NSNotificationCenter defaultCenter] postNotificationName:IMSiLopExtensionDidReceiveUpdateAttributeSuccess object:self userInfo:data]; } if ([topic isEqualToString:@"/thing/status"]) { [[NSNotificationCenter defaultCenter] postNotificationName:IMSiLopExtensionDidReceiveUpdateDeviceStateSuccess object:self userInfo:data]; } } } if (replyDict == nil) { return; } } - (BOOL)shouldHandle:(NSString * _Nonnull)topic { // 需要设什么topic,返回什么topic if ([topic isEqualToString:@"/thing/properties"] || [topic isEqualToString:@"/thing/status"]) { return YES; } return NO; } @end 【3】增加代理监听、增加属性 @interface IMSWidgetDeviceController () < LKAppExpConnectListener> // 本地控制 @property (nonatomic, strong) IMSWidgetDeviceListener *imsWidgetDeviceListener; 【4】在ViewDidLoad 中增加监听 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. // 监听云端设备属性变更 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dididReceiveUpdateAttributeNoti:) name:IMSiLopExtensionDidReceiveUpdateAttributeSuccess object:nil]; // 监听云端设备状态变更 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dididReceiveUpdateDeviceStateNoti:) name:IMSiLopExtensionDidReceiveUpdateDeviceStateSuccess object:nil]; } 【5】自行处理下行通知 // 云端属性数据下发 - (void)dididReceiveUpdateAttributeNoti:(NSNotification *)info { } // 云端状态数据下发 - (void)dididReceiveUpdateDeviceStateNoti:(NSNotification *)info { } 【6】更改属性方法 IMSThing *thingShell = [kIMSThingManager buildThing:iotId]; [[thingShell getThingActions] setProperties:@{propertyIdentifierName:value} responseHandler:^(IMSThingActionsResponse * _Nullable response) { if (response.success) { // 成功 } else { // 失败 } }]; 【7】释放资源 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 移除长链接相关 [[LKAppExpress sharedInstance] removeConnectListener:self]; [[LKAppExpress sharedInstance] removeDownStreamListener:self.imsWidgetDeviceListener]; } - (void)dealloc { [kIMSThingManager destroyThing:self.thingShell]; [[NSNotificationCenter defaultCenter] removeObserver:self]; }
- 场景小组件