更新时间:2023-07-13 07:14:39下载pdf
涂鸦设备详情 UI 业务包提供了以下功能:
在工程的 Podfile
文件中添加业务包组件,并执行 pod update
命令。
source "https://github.com/tuya/tuya-private-specs"
source 'https://cdn.cocoapods.org/'
target 'your_target_name' do
# 添加设备详情 UI 业务包
pod 'ThingSmartDeviceDetailBizBundle'
# 如果使用蓝牙功能,需要引入蓝牙相关组件
# pod 'ThingBluetoothInterface'
# pod 'ThingBLEMeshInterfaceImpl'
end
设备详情 UI 业务包涉及到设备图标上传时,需要使用系统相册和相机权限。因此,会涉及到部分苹果隐私权限的声明。
您需要在工程的 info.plist
中添加如下权限声明:
<!-- 相册 -->
<key>NSPhotoLibraryUsageDescription</key>
<string>App 需要您的同意,才能访问相册</string>
<!-- 相机 -->
<key>NSCameraUsageDescription</key>
<string>App 需要您的同意,才能访问相机</string>
如果接入了蓝牙设备,使用创建群组或者移除设备等依赖蓝牙能力的业务,需要在info.plist
中添加如下权限声明:
<!-- 蓝牙 -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>这将允许应用程序找到并连接蓝牙配件。这个应用程序也可以使用蓝牙定位蓝牙设备。</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>如果需要添加或使用蓝牙设备,请开启手机蓝牙功能。</string>
在主工程中,新建 deviceDetailConfig.json
文件。如果已经存在该文件,则不用再新建。
在 deviceDetailConfig.json
中添加以下内容:
[
{
"name": "headerSection",
"items": [
{
"cellType": "header"
},{
"cellType": "device_info"
},{
"cellType": "net_setting"
},{
"cellType":"group_edit_devices"
}
]
},{
"name": "offLineWarnSection",
"header": {
"cellType":"section_off_line_warn"
},
"items": [
{
"cellType" : "off_line_warn"
}
]
},{
"name": "otherSection",
"header": {
"cellType":"section_other"
},
"items": [
{
"cellType":"bind_multi_control_link"
},
{
"cellType":"group_create"
},
{
"cellType":"help_and_feedback"
},
{
"cellType":"add_icon_to_home_screen"
},
{
"cellType":"show_infrared_gateway_sub_device"
},
{
"cellType":"check_device_network"
},
{
"cellType":"check_firmware_update"
}
]
},{
"name": "footerSection",
"items": [
{
"cellType":"footer"
}
],
"margin": {
"top": 16
}
}
]
自定义设备详情。
deviceDetail
数组 item
的顺序影响设备详情页 item
展示的顺序。如果移除 item
,则相应也会移除设备详情页子功能。
deviceDetail 类型 |
设备详情页子功能 |
---|---|
header | 查看修改设备图标,名称,位置 |
device_info | 设备信息 |
net_setting | 设备备用网络 |
off_line_warn | 设备离线提醒 |
section_other | 分区头,无实际功能 |
group_edit_devices | 编辑群组 |
group_create | 创建群组 |
add_icon_to_home_screen | 添加到主屏幕 |
show_infrared_gateway_sub_device | 展示遥控器 |
footer | 移除设备 |
ThingSmartHomeDataProtocol
协议已废弃,推荐使用ThingFamilyProtocol
协议。
/**
要使用该 API 获取当前家庭,请务必在更新当前家庭 ID 的时候使用该协议的’updateCurrentHomeId:‘Api。
获取当前的家庭,当前没有家庭的时候,返回 nil。
@return ThingSmartHome
*/
- (ThingSmartHome *)getCurrentHome;
Objective-C 示例:
#import <ThingSmartBizCore/ThingSmartBizCore.h>
#import <ThingModuleServices/ThingSmartHomeDataProtocol.h>
- (void)initCurrentHome {
// 注册要实现的协议
[[ThingSmartBizCore sharedInstance] registerService:@protocol(ThingSmartHomeDataProtocol) withInstance:self];
}
// 实现对应的协议方法
- (ThingSmartHome *)getCurrentHome {
ThingSmartHome *home = [ThingSmartHome homeWithHomeId:@"当前家庭 ID"];
return home;
}
Swift 示例:
import ThingSmartDeviceKit
class ThingMessageCenterTest: NSObject,ThingSmartHomeDataProtocol{
func test() {
ThingSmartBizCore.sharedInstance().registerService(ThingSmartHomeDataProtocol.self, withInstance: self)
}
func getCurrentHome() -> ThingSmartHome! {
let home = ThingSmartHome.init(homeId: 111)
return home
}
}
蓝牙功能:在 Podfile、Info.plist
添加相关依赖和声明后,在业务使用前,调用蓝牙启动方法。
#import <ThingBluetoothInterface/ThingBluetoothInterface.h>
[TheBLEInterfaceService startScan];
方法 | 参数 |
---|---|
跳转到网络检测页 | 设备 ID |
跳转到设备详情页,以 Push 方式 | ThingSmartDeviceModel 或 ThingSmartGroupModel |
查询红外子设备是否需要显示 | devId 、spaceId |
获取红外子设备是否显示 | devId 、spaceId |
设备显示红外子设备状态变化通知名称 |
///跳转到网络检测页
/// @param devId 设备 ID
- (void)gotoDeviceDetailNetworkViewControllerWithDeviceId:(NSString *)devId;
///跳转到设备详情页,以 push 方式
/// @param device 设备
/// @param group 群组,若有就传
- (void)gotoDeviceDetailDetailViewControllerWithDevice:(ThingSmartDeviceModel *)device group:(ThingSmartGroupModel *)group;
@optional
/// 查询红外子设备是否需要显示
/// @param devId 设备 ID,传入非红外线网关或者子设备将返回 YES
/// @param spaceId 空间 ID
/// @return YES,展示。NO,不展示。
- (BOOL)getInfraredDisplayStatusWithDevId:(nullable NSString *)devId spaceId:(long long)spaceId;
@optional
/// 判断设备是否开启了显示红外子设备
/// @param devId 设备 ID
/// @param spaceId 空间 ID
/// @return YES,展示。NO,不展示。
- (BOOL)cacheOfInfraredDisplayStatusWithDevId:(nullable NSString *)devId spaceId:(long long)spaceId;
@optional
/// 设备显示红外子设备状态变化通知名称
- (nullable NSNotificationName)subDeviceDisplayStatusChangeNotificationName;
Objective-C 示例:
#import <ThingSmartBizCore/ThingSmartBizCore.h>
#import <ThingModuleServices/ThingDeviceDetailProtocol.h>
id<ThingDeviceDetailProtocol> impl = [[ThingSmartBizCore sharedInstance] serviceOfProtocol:@protocol(ThingDeviceDetailProtocol)];
// 跳转到设备网络检测页
[impl gotoDeviceDetailNetworkViewControllerWithDeviceId:@"设备 ID"];
// 跳转到设备详情页,以 push 方式
// 如果是设备,new ThingSmartDevice
ThingSmartDevice * device = [ThingSmartDevice deviceWithDeviceId:@"设备 ID"]
[impl gotoDeviceDetailDetailViewControllerWithDevice: device.deviceModel group: nil];
// 如果是群组,new ThingSmartGroup
ThingSmartGroup * group = [ThingSmartDevice groupWithGroupId:@"群组 ID"]
[impl gotoDeviceDetailDetailViewControllerWithDevice: nil group: group.deviceModel];
Swift 示例:
let impl = ThingSmartBizCore.sharedInstance().service(of: ThingDeviceDetailProtocol.self) as? ThingDeviceDetailProtocol
//跳转到设备网络检测页
impl?.gotoDeviceDetailNetworkViewController(withDeviceId: "设备 ID")
// 跳转到设备详情页,以 push 方式
//如果是设备,new ThingSmartDevice
let device = ThingSmartDevice.init(deviceId: "vdevo160888044089994")
impl?.gotoDeviceDetailDetailViewController(withDevice: device?.deviceModel, group: nil)
//如果是群组,new ThingSmartGroup
let group = ThingSmartGroup.init(groupId: "群组 ID")
impl?.gotoDeviceDetailDetailViewController(withDevice: nil, group: group?.groupModel)
添加到主屏幕 会在屏幕上创建书签,用户单击书签后可以唤起 App 进入设备面板页面。您需要进行简单的配置,才能支持这个功能。
请在 deviceDetailConfig.json
中添加add_icon_to_home_screen
,否则该功能不会展示。
配置 thing_custom_config.json
文件中的 appScheme,例如此处的值为: “您的 appScheme”,您需要将它替换为一个自定义的值。
{
"config": {
...
"appScheme": "您的 appScheme"
},
...
}
在添加 App 的 URL Scheme
中添加上 thing_custom_config.json
文件中 appScheme
对应的值,例如上一步配置的 "您的 appScheme"
,同样,您需要将它替换为一个自定义的值。
在 AppDelegate
中处理路由事件:
Objective-C 示例:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options {
if ([[url.scheme lowercaseString] isEqualToString:@"oralcaretest"]) {
NSDictionary *params = [self dictionaryFromQuery:url.query usingEncoding:NSUTF8StringEncoding];
NSString *host = url.host;
if ([host isEqualToString:@"panelEx"]) {
id <ThingPanelProtocol> impl = [[ThingSmartBizCore sharedInstance] serviceOfProtocol:@protocol(ThingPanelProtocol)];
ThingSmartDevice *device = [ThingSmartDevice deviceWithDeviceId:params[@"devId"]?: @""];
[impl getPanelViewControllerWithDeviceModel:device.deviceModel initialProps:nil contextProps:nil completionHandler:^(__kindof UIViewController * _Nullable panelViewController, NSError * _Nullable error) {
if (error) {
NSLog(@"Load error: %@", error);
}
}];
}
return YES;
}
return NO;
}
- (NSDictionary *)dictionaryFromQuery:(NSString *)query usingEncoding:(NSStringEncoding)encoding {
if (!([query isKindOfClass:[NSString class]] && query.length > 0)) {
return nil;
}
NSCharacterSet *delimiterSet = [NSCharacterSet characterSetWithCharactersInString:@"&;"];
NSMutableDictionary* pairs = [NSMutableDictionary dictionary];
NSScanner* scanner = [[NSScanner alloc] initWithString:query];
while (![scanner isAtEnd]) {
NSString* pairString = nil;
[scanner scanUpToCharactersFromSet:delimiterSet intoString:&pairString];
[scanner scanCharactersFromSet:delimiterSet intoString:NULL];
NSArray* kvPair = [pairString componentsSeparatedByString:@"="];
if (kvPair.count == 2) {
NSString* key = [[kvPair objectAtIndex:0]
stringByReplacingPercentEscapesUsingEncoding:encoding];
NSString* value = [[kvPair objectAtIndex:1]
stringByReplacingPercentEscapesUsingEncoding:encoding];
[pairs setObject:value forKey:key];
}
}
return [NSDictionary dictionaryWithDictionary:pairs];
}
Swift 示例:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if let scheme = url.scheme, scheme.lowercased() == "oralcaretest" {
let params = self.params(from: url.query, .utf8)
if let host = url.host, host == "panelEx", let devId = params?["devId"] as? String, let device = ThingSmartDevice(deviceId: devId) {
let impl: ThingPanelProtocol? = ThingSmartBizCore.sharedInstance().service(of: ThingPanelProtocol.self) as? ThingPanelProtocol
impl?.getPanelViewController(with: device.deviceModel, initialProps: nil, contextProps: nil, completionHandler: { vc, error in
if error != nil {
print(error!.localizedDescription)
}else{
print("push the vc")
}
})
}
return true
}
return false
}
func params(from query: String?, _ encoding: String.Encoding) -> Dictionary<String, Any>? {
guard let queryString = query, queryString.count > 0 else {
return nil
}
let set = CharacterSet(charactersIn: "&;")
var pairs = Dictionary<String, Any>()
let scanner = Scanner(string: queryString)
while !scanner.isAtEnd {
var pairString: NSString? = ""
scanner.scanUpToCharacters(from: set, into: &pairString)
scanner.scanCharacters(from: set, into: nil)
if let kvPair = pairString?.components(separatedBy: "="), kvPair.count == 2 {
let key: String = kvPair.first!.removingPercentEncoding!
let value: String = kvPair.last!
pairs[key] = value
}
}
return pairs
}
默认情况下,SDK 不会展示设备信息中的位置信息隐藏功能。如果需要展示,请在thing_custom_config.json
文件中配置 is_support_home_manager
为 true。
{
"config": {
...
"is_support_home_manager": true,
},
...
}
需要自定义实现 ThingDeviceDetailExternalProtocol
。
/// @brief 移除设备后,自定义回退到哪个页面
/// @return YES 自定义处理,NO 默认逻辑
- (BOOL)customExitWhenDeleted;
自定义子功能可以通过配置 deviceDetailConfig.json
来实现。在 deviceDetailConfig.json
文件的 deviceDetail
插入自定义 type
。
type
值必须以 c_
开头。例如,插入 c_test_insert
、c_test_async_insert
。
[
{
"name": "headerSection",
"items": [
{
"cellType": "header"
},{
"cellType": "device_info"
},{
"cellType": "net_setting"
},{
"cellType":"group_edit_devices"
}
]
},{
"name": "offLineWarnSection",
"header": {
"cellType":"section_off_line_warn"
},
"items": [
{
"cellType" : "off_line_warn"
}
]
},{
"name": "otherSection",
"header": {
"cellType":"section_other"
},
"items": [
{
"cellType":"bind_multi_control_link"
},
{
"cellType":"group_create"
},
{
"cellType":"help_and_feedback"
},
{
"cellType":"add_icon_to_home_screen"
},
{
"cellType":"show_infrared_gateway_sub_device"
},
{
"cellType":"check_device_network"
},
{
"cellType":"check_firmware_update"
},
{
"cellType":"c_test_insert"
},
{
"cellType":"c_test_async_insert"
}
]
},{
"name": "footerSection",
"items": [
{
"cellType":"footer"
}
],
"margin": {
"top": 16
}
}
]
接口说明:清空数据
进行自定义 item
插入前,调用此方法可清空数据。
/// 清空设置的自定义 item
- (void)clearInsertItem;
接口说明:同步返回 item 数据
/// 设置-》同步处理 item 插入的回调。insertDevMenuItemBlock 会在设备详情刷新时候回调,type 为配置文件中的 cellType
-(void)insertDevMenuItem:(InsertDevMenuItemBlock) insertDevMenuItemBlock customType:(NSString *)type;
//@param type configList.json 里自己添加的 type
//@param device 设备模型
//@param group 群组模型。根据 group 是否为 nil,来判断设备还是群组
//@return 遵守 ThingDeviceDetailCustomMenuModel 协议的对象。返回 nil,该 type 的 item 则不会显示
typedef id<ThingDeviceDetailCustomMenuModel> _Nullable (^InsertDevMenuItemBlock)(NSString* _Nonnull type,
ThingSmartDeviceModel* _Nullable device,
ThingSmartGroupModel* _Nullable group);
接口说明:异步回调 item 数据
/// 设置-》异步处理 item 插入的回调,insertDevMenuItemAsyncBlock 会在设备详情刷新时候回调,type 为配置文件中的 cellType
-(void)insertDevMenuItemAsync:(InsertDevMenuItemAsyncBlock) insertDevMenuItemAsyncBlock customType:(NSString *)type;
//异步处理 item 插入,当异步操作结束以后,调用 complete(id<ThingDeviceDetailCustomMenuMode>),回调数据给设备详情,并进行刷新列表。
typedef void (^InsertDevMenuItemAsyncBlock)(NSString* _Nonnull type,
ThingSmartDeviceModel* _Nullable device,
ThingSmartGroupModel* _Nullable group,
InsertDevMenuItemComplete _Nonnull complete);
首先,新建一个 Model 类,遵守 ThingDeviceDetailCustomMenuModel
协议。
Objective-C 示例:
//自定义一个类遵守 ThingDeviceDetailCustomMenuModel 协议
@interface CustomMenuModel : NSObject<ThingDeviceDetailCustomMenuModel>
///标题
@property (nonatomic,copy) NSString *title;
///子标题
@property (nonatomic,copy) NSString *detail;
@end
@implementation CustomMenuModel
@end
Swift 示例:
class CustomMenuModel: NSObject, ThingDeviceDetailCustomMenuModel{
var title : String?
var detail : String?
}
然后,设置数据回调的 block
。
Objective-C 示例:
id<ThingDeviceDetailProtocol> impl = [[ThingSmartBizCore sharedInstance] serviceOfProtocol:@protocol(ThingDeviceDetailProtocol)];
[impl clearInsertItem];// 插入前清空数据
[impl insertDevMenuItem:^ id<ThingDeviceDetailCustomMenuModel> (NSString * _Nonnull type, ThingSmartDeviceModel * _Nonnull device, ThingSmartGroupModel * _Nonnull group) {
if ([type isEqualToString:@"c_test_insert"]) {
CustomMenuModel *model = [CustomMenuModel new];
if (group) { //根据 group 是否为 nil,来判断设备还是群组
model.title = type;
model.detail = @"group";
}else{
model.title = type;
model.detail = @"device";
}
return model;
}
return nil;
} customType:@"c_test_insert"];
[impl insertDevMenuItemAsync:^(NSString * _Nonnull type, ThingSmartDeviceModel * _Nonnull device, ThingSmartGroupModel * _Nonnull group, InsertDevMenuItemComplete _Nonnull complete) {
if ([type isEqualToString:@"c_test_async_insert"]) {
//耗时操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CustomMenuModel *model = [CustomMenuModel new];
if (group) { //根据 group 是否为 nil,来判断设备还是群组
model.title = type;
model.detail = @"group";
}else{
model.title = type;
model.detail = @"device";
}
complete(model);
});
}
} customType:@"c_test_async_insert"];
Swift 示例:
let impl = ThingSmartBizCore.sharedInstance().service(of: ThingDeviceDetailProtocol.self) as? ThingDeviceDetailProtocol
impl?.clearInsertItem // 插入前清空数据
impl?.insertDevMenuItem({ (type, deviceModel, groupModel) -> ThingDeviceDetailCustomMenuModel? in
if type == "c_test_insert" {//根据 group 是否为 nil,来判断设备还是群组
let model = CustomMenuModel.init()
if groupModel != nil {
model.title = type
model.detail = "group"
}else{
model.title = type
model.detail = "device"
}
return model;
}
return nil;
} , customType: "c_test_insert")
impl?.insertDevMenuItemAsync({ (type, deviceModel, groupModel, complete) in
if type == "c_test_async_insert" {
//耗时操作
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
let model = CustomMenuModel.init()
if groupModel != nil {
model.title = type
model.detail = "group"
}else{
model.title = type
model.detail = "device"
}
complete(model);
}
}
} , customType: "c_test_async_insert");
Objective-C 示例:
id<ThingDeviceDetailProtocol> impl = [[ThingSmartBizCore sharedInstance] serviceOfProtocol:@protocol(ThingDeviceDetailProtocol)];
[impl clickMenuItem: ^(NSString * _Nonnull type, ThingSmartDeviceModel * _Nonnull device, ThingSmartGroupModel * _Nonnull group) {
NSLog(@"clickItem: type:%@",type);
}];
Swift 示例:
let impl = ThingSmartBizCore.sharedInstance().service(of: ThingDeviceDetailProtocol.self) as? ThingDeviceDetailProtocol
impl?.clickMenuItem({ (type, deviceModel, groupModel) in
print("clickItem: type:"+type);
})
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈