Device Details UI BizBundle

Last Updated on : 2023-05-22 06:38:28

Device Details UI BizBundle supports the following features:

  • Modify device information, such as the device icon, device name, and room.
  • Query device information, such as device ID, signal strength, and more.
  • Check for firmware updates. OTA UI BizBundle must be additionally integrated.
  • Provide FAQ and feedback. FAQ UI BizBundle must be additionally integrated.
  • Create or modify device groups. Starting SDK v3.25.0, Group Management UI BizBundle must be additionally integrated.
  • Configure backup Wi-Fi networks.
  • Check device networks.
  • Notify users of devices getting offline.
  • Remove devices.
  • Add shortcuts to the home screen.
  • Show remote controls.

Integrate with the UI BizBundle

Podfile

Add the components of the Device Details UI BizBundle to the Podfile and run the command pod update.

source "https://github.com/tuya/tuya-pod-specs"
source 'https://cdn.cocoapods.org/'
platform :ios, '11.0'

target 'your_target_name' do
# Adds the Device Details UI BizBundle.
pod 'TuyaSmartDeviceDetailBizBundle'
end

Permissions

The UI BizBundle supports the upload of device icons. To implement this feature, the permissions on the system album and camera must be granted. This requires specific declarations of privacy and permissions from Apple. Add the following permission declaration to info.plist of your project:

<!-- Album -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Authorizes the app to access the album of the mobile phone</string>
<!-- Camera -->
<key>NSCameraUsageDescription</key>
<string>Authorizes the app to access the camera of the mobile phone</string>

Configuration file

  1. Create the configuration file deviceDetailConfig.json in the main project. If the file already exists, skip the creation.

  2. Add the following content to 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
            }
        }
    ]
    
  3. Customize device details.

    The sequence of the item parameter in the deviceDetail array determines the sequence in which each item is displayed on the device details page. If item is removed, the associated device feature will also be removed from the device details page.

    Item of deviceDetail Device feature
    header View and modify the device icon, device name, and location.
    device_info Device information
    net_setting Display backup Wi-Fi networks.
    off_line_warn Notify users of devices getting offline.
    group_edit_devices Modify a group
    group_create Create a group
    help_and_feedback Provide FAQ and feedback. FAQ UI BizBundle must be additionally integrated.
    check_firmware_update Check for firmware updates. OTA UI BizBundle must be additionally integrated.
    add_icon_to_home_screen Add shortcuts to the home screen.
    show_infrared_gateway_sub_device Show remote controls.
    footer Remove devices.

Depend on services

TYSmartHomeDataProtocol is deprecated and TYFamilyProtocol is recommended.

/**
To use this API method to get the current home data, you must use `'updateCurrentHomeId:' Api` of the protocol when the current home ID is updated.
Returns the current home. If the current user does not have a home, `nil` is returned.

@return TuyaSmartHome
*/
- (TuyaSmartHome *)getCurrentHome;

ObjC:

#import <TuyaSmartBizCore/TuyaSmartBizCore.h>
#import <TYModuleServices/TYSmartHomeDataProtocol.h>

- (void)initCurrentHome {
	// Registers the protocol to be implemented.
	[[TuyaSmartBizCore sharedInstance] registerService:@protocol(TYSmartHomeDataProtocol) withInstance:self];
}

// Implements the protocol method.
- (TuyaSmartHome *)getCurrentHome {
	TuyaSmartHome *home = [TuyaSmartHome homeWithHomeId:@"Current home ID"];
	return home;
}

Swift:

import TuyaSmartDeviceKit

class TYMessageCenterTest: NSObject,TYSmartHomeDataProtocol{

	func test() {
		TuyaSmartBizCore.sharedInstance().registerService(TYSmartHomeDataProtocol.self, withInstance: self)
	}

	func getCurrentHome() -> TuyaSmartHome! {
		let home = TuyaSmartHome.init(homeId: 111)
		return home
	}

}

Implement optional features

Make API requests

Method Parameter
Navigate to the network detection page The device ID.
Navigate to device details by means of push TuyaSmartDeviceModel/TuyaSmartGroupModel
Check whether to display infrared sub-devices devId, spaceId
Check whether displaying infrared sub-devices is enabled. devId, spaceId
Display the notification of infrared sub-device status changes -

API description

/// Navigates to the page of network detection.
/// @param devId The device ID.
- (void)gotoDeviceDetailNetworkViewControllerWithDeviceId:(NSString *)devId;

/// Navigates to device details by means of push.
/// @param device The device.
/// @param group The group if any. It is optional.
- (void)gotoDeviceDetailDetailViewControllerWithDevice:(TuyaSmartDeviceModel *)device group:(TuyaSmartGroupModel *)group;

@optional
/// Checks whether to display infrared sub-devices.
/// @param devId The device ID. If a non-infrared gateway or sub-device is passed in, `YES` is returned.
/// @param spaceId The space ID.
/// @return The return value. Valid values: `YES`: display. `NO`: not display.
- (BOOL)getInfraredDisplayStatusWithDevId:(nullable NSString *)devId spaceId:(long long)spaceId;

@optional
/// Checks whether displaying infrared sub-devices is enabled.
/// @param devId The device ID.
/// @param spaceId The space ID.
/// @return The return value. Valid values: `YES`: display. `NO`: not display.
- (BOOL)cacheOfInfraredDisplayStatusWithDevId:(nullable NSString *)devId spaceId:(long long)spaceId;

@optional
/// Displays the notification of infrared sub-device status changes.
- (nullable NSNotificationName)subDeviceDisplayStatusChangeNotificationName;

ObjC:

#import <TuyaSmartBizCore/TuyaSmartBizCore.h>
#import <TYModuleServices/TYDeviceDetailProtocol.h>

id<TYDeviceDetailProtocol> impl = [[TuyaSmartBizCore sharedInstance] serviceOfProtocol:@protocol(TYDeviceDetailProtocol)];

// Navigates to the page of network detection.
[impl gotoDeviceDetailNetworkViewControllerWithDeviceId:@"Device ID"];

	// Navigate to device details by means of push

	// For a device, `new TuyaSmartDevice` is called.
TuyaSmartDevice * device = [TuyaSmartDevice deviceWithDeviceId:@"Device ID"]
	[impl gotoDeviceDetailDetailViewControllerWithDevice: device.deviceModel group: nil];
	// For a group, `new TuyaSmartGroup` is called.
TuyaSmartGroup * group = [TuyaSmartDevice groupWithGroupId:@"Group ID"]
	[impl gotoDeviceDetailDetailViewControllerWithDevice: nil group: group.deviceModel];

Swift:

let impl = TuyaSmartBizCore.sharedInstance().service(of: TYDeviceDetailProtocol.self) as? TYDeviceDetailProtocol
// Navigates to the page of network detection.
impl?.gotoDeviceDetailNetworkViewController(withDeviceId: "Device ID")

	// Navigate to device details by means of push

	// For a device, `new TuyaSmartDevice` is called.
	let device = TuyaSmartDevice.init(deviceId: "vdevo160888044089994")
	impl?.gotoDeviceDetailDetailViewController(withDevice: device?.deviceModel, group: nil)
	// For a group, `new TuyaSmartGroup` is called.
	let group = TuyaSmartGroup.init(groupId: "Group ID")
	impl?.gotoDeviceDetailDetailViewController(withDevice: nil, group: group?.groupModel)

Navigate to device panels from shortcuts on home screen

Add to Home Screen: This feature allows users to create a bookmark on the home screen. This bookmark works as the shortcut of a device panel. After users tap this bookmark, your app is evoked and users are navigated to the target device panel. To enable this feature, perform the following steps:

  1. Add add_icon_to_home_screen to deviceDetailConfig.json. Otherwise, this feature is unavailable.

  2. Set appScheme in the file ty_custom_config.json. In the following example, you need to replace the default value Your appScheme with another value.

    {
    	"config": {
    		...
    		"appScheme": "Your appScheme"
    	},
    	...
    }
    
  3. Add the value of appScheme in the file ty_custom_config.json to URL Scheme. In the preceding example, this default value is Your appScheme. It must be replaced with another value.

  4. Process routing events in AppDelegate:

    ObjC:

    - (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 <TYPanelProtocol> impl = [[TuyaSmartBizCore sharedInstance] serviceOfProtocol:@protocol(TYPanelProtocol)];
                TuyaSmartDevice *device = [TuyaSmartDevice 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 = TuyaSmartDevice(deviceId: devId) {
    
                let impl: TYPanelProtocol? = TuyaSmartBizCore.sharedInstance().service(of: TYPanelProtocol.self) as? TYPanelProtocol
                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
    }
    

Select album photos or take photos with camera

You can enable device feature icon editing and allow users to select album photos or take photos with camera. For this purpose, configure ty_custom_config.json with the following options:

  • Set is_enable_device_icon_edit to true, so the feature icon of selecting album photos and taking photos with camera for common devices can be edited.

  • Set is_enable_group_icon_edit to true, so the feature icon of selecting album photos and taking photos with camera for group devices can be edited.

    {
        "config": {
            ...
            "is_enable_device_icon_edit": true,
            "is_enable_group_icon_edit": true
        },
    ...
    }
    

Hide location data from device details

By default, the SDK does not show the feature that allows users to hide location data from device details. To show the feature, set is_support_home_manager to true in ty_custom_config.json.

{
    "config": {
        ...
        "is_support_home_manager": true,
    },
   ...
}

Customize specific features

Specific features can be implemented with the configuration file deviceDetailConfig.json. You can add the custom parameter type to deviceDetail in deviceDetailConfig.json.

The value of type must start with c_. For example, c_test_insert and c_test_async_insert can be added.

[
    {
        "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
        }
    }
]

Return item data

Synchronous callback

/// Implements the synchronous callback. `insertDevMenuItemBlock` returns the callback when device details are refreshed. `type` is equivalent to `cellType` in the configuration file.
-(void)insertDevMenuItem:(InsertDevMenuItemBlock) insertDevMenuItemBlock customType:(NSString *)type;
//@param type The custom type specified in `configList.json`.
//@param device  The device model.
//@param group   The group model. If `group` is `nil`, device data is returned. Otherwise, group data is returned.
//@return The object that follows the protocol `TYDeviceDetailCustomMenuModel`. If `nil` is returned, this type of item is not displayed.
typedef id<TYDeviceDetailCustomMenuModel> _Nullable (^InsertDevMenuItemBlock)(NSString* _Nonnull type,
		TuyaSmartDeviceModel* _Nullable device,
		TuyaSmartGroupModel* _Nullable group);

Asynchronous callback

/// Implements the asynchronous callback. `insertDevMenuItemAsyncBlock` returns the callback when device details are refreshed. `type` is equivalent to `cellType` in the configuration file.
-(void)insertDevMenuItemAsync:(InsertDevMenuItemAsyncBlock) insertDevMenuItemAsyncBlock customType:(NSString *)type;
// Inserts the asynchronous operation to process the item. At the end of the operation, call `complete(id<TYDeviceDetailCustomMenuMode>)`. The result data is returned to the device details module and the list is refreshed.
typedef void (^InsertDevMenuItemAsyncBlock)(NSString* _Nonnull type,
		TuyaSmartDeviceModel* _Nullable device,
		TuyaSmartGroupModel* _Nullable group,
		InsertDevMenuItemComplete _Nonnull complete);

Example

Step 1: Create a Model class

ObjC:

// Customizes a class that adopts the protocol `TYDeviceDetailCustomMenuModel`.
@interface CustomMenuModel : NSObject<TYDeviceDetailCustomMenuModel>
/// The title.
@property (nonatomic,copy) NSString *title;
/// The subtitle.
@property (nonatomic,copy) NSString *detail;
@end

@implementation CustomMenuModel
@end

Swift:

class CustomMenuModel: NSObject, TYDeviceDetailCustomMenuModel{
	var title : String?
	var detail : String?
}

Step 2: Configure the callback block

ObjC:

id<TYDeviceDetailProtocol> impl = [[TuyaSmartBizCore sharedInstance] serviceOfProtocol:@protocol(TYDeviceDetailProtocol)];

		[impl insertDevMenuItem:^ id<TYDeviceDetailCustomMenuModel> (NSString * _Nonnull type, TuyaSmartDeviceModel * _Nonnull device, TuyaSmartGroupModel * _Nonnull group) {
			if ([type isEqualToString:@"c_test_insert"]) {
				CustomMenuModel *model = [CustomMenuModel new];
				if (group) { // If `group` is `nil`, device data is returned. Otherwise, group data is returned.
					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, TuyaSmartDeviceModel * _Nonnull device, TuyaSmartGroupModel * _Nonnull group, InsertDevMenuItemComplete _Nonnull complete) {
			if ([type isEqualToString:@"c_test_async_insert"]) {
			// The time-consuming operation.
			dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
				CustomMenuModel *model = [CustomMenuModel new];
				if (group) { // If `group` is `nil`, device data is returned. Otherwise, group data is returned.
					model.title = type;
					model.detail = @"group";
				}else{
					model.title = type;
					model.detail = @"device";
				}
				complete(model);
			});
			}
            } customType:@"c_test_insert"];

Swift:

let impl = TuyaSmartBizCore.sharedInstance().service(of: TYDeviceDetailProtocol.self) as? TYDeviceDetailProtocol

	impl?.insertDevMenuItem({ (type, deviceModel, groupModel) -> TYDeviceDetailCustomMenuModel? in
			if type == "c_test_insert" {// If `group` is `nil`, device data is returned. Otherwise, group data is returned.
				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" {
				// The time-consuming operation.
				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");

Insert handler of item tapping event

ObjC:

	id<TYDeviceDetailProtocol> impl = [[TuyaSmartBizCore sharedInstance] serviceOfProtocol:@protocol(TYDeviceDetailProtocol)];
		[impl clickMenuItem: ^(NSString * _Nonnull type, TuyaSmartDeviceModel * _Nonnull device, TuyaSmartGroupModel * _Nonnull group) {
			NSLog(@"clickItem: type:%@",type);
		}];

Swift:

let impl = TuyaSmartBizCore.sharedInstance().service(of: TYDeviceDetailProtocol.self) as? TYDeviceDetailProtocol

impl?.clickMenuItem({ (type, deviceModel, groupModel) in
			print("clickItem: type:"+type);
	})