From d93de8833865eb833ca72320f317bf92ba2ae52a Mon Sep 17 00:00:00 2001
From: JLChen <551775569@qq.com>
Date: 星期四, 08 七月 2021 15:38:24 +0800
Subject: [PATCH] 2021-07-08 1.更新

---
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.h                     |   15 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.m      |  362 ++++++
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo.xcodeproj/project.pbxproj          |   24 
 EZSDK/EZSDK/EZSDK.h                                                                           |   15 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.m                     |   33 
 EZSDK.IOS/EZSDK.IOS/ApiDefinition.cs                                                          |  179 ++
 Demo/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m                                       |    8 
 EZSDK/EZSDK/EZ/TableViewCells/DeviceListCell.m                                                |    5 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.m | 1839 ++++++++++++++++++++++++++++++++
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.h |  440 +++++++
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.h      |  200 +++
 EZSDK/EZSDK/EZSDK.m                                                                           |   29 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.h                 |    1 
 EZSDK.IOS/EZSDK.IOS/Properties/AssemblyInfo.cs                                                |    2 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/AddDevice.storyboard    |   14 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard       |   14 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.m                 |    5 
 EZSDK/EZSDK/DeviceInfo.h                                                                      |   10 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/ViewController.m                   |   46 
 EZSDK.IOS/EZSDK.IOS/Library/libEZSDK.a                                                        |    0 
 Demo/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard                                          |   38 
 EZSDK/EZSDK/EZ/Global/GlobalKit.m                                                             |    4 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m    |    4 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZHttpUtil.m                |   28 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYModel.h          |   22 
 EZSDK/EZSDK/EZ/Global/EZHttpUtil.m                                                            |   28 
 Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/AppDelegate.m                      |    6 
 EZSDK/EZSDK/EZ/Global/GlobalKit.h                                                             |    1 
 28 files changed, 3,235 insertions(+), 137 deletions(-)

diff --git a/Demo/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard b/Demo/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
index 4c47933..97f81ae 100644
--- a/Demo/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
+++ b/Demo/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
@@ -243,8 +243,8 @@
                                             <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                             <nil key="highlightedColor"/>
                                         </label>
-                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hZX-eZ-E0u">
-                                            <rect key="frame" x="127" y="29" width="39" height="39"/>
+                                        <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hZX-eZ-E0u">
+                                            <rect key="frame" x="245" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="4QQ-tz-dPq"/>
                                                 <constraint firstAttribute="height" constant="39" id="RuZ-Pc-8zE"/>
@@ -258,7 +258,7 @@
                                             </connections>
                                         </button>
                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AmG-2j-Y75">
-                                            <rect key="frame" x="186" y="29" width="39" height="39"/>
+                                            <rect key="frame" x="127" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="Q42-XD-P1b"/>
                                                 <constraint firstAttribute="height" constant="39" id="iDX-Vm-hmw"/>
@@ -288,7 +288,7 @@
                                             </constraints>
                                         </imageView>
                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0cb-tT-6Se">
-                                            <rect key="frame" x="245" y="29" width="39" height="39"/>
+                                            <rect key="frame" x="186" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="Mps-h7-nX0"/>
                                                 <constraint firstAttribute="height" constant="39" id="hNG-1A-X3w"/>
@@ -316,12 +316,13 @@
                                     <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
                                     <constraints>
                                         <constraint firstItem="4wC-NG-1q2" firstAttribute="leading" secondItem="Iet-JC-0rQ" secondAttribute="leading" constant="5" id="2lM-8U-Coj"/>
-                                        <constraint firstItem="AmG-2j-Y75" firstAttribute="leading" secondItem="hZX-eZ-E0u" secondAttribute="trailing" constant="20" id="3AL-W4-tN5"/>
                                         <constraint firstAttribute="bottom" secondItem="AmG-2j-Y75" secondAttribute="bottom" constant="5" id="4hD-YQ-TQt"/>
                                         <constraint firstItem="4wC-NG-1q2" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="CpW-TJ-kmv"/>
                                         <constraint firstItem="yuu-Ju-MKr" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="Exf-xl-NwN"/>
+                                        <constraint firstItem="ad0-s7-tSM" firstAttribute="leading" secondItem="hZX-eZ-E0u" secondAttribute="trailing" constant="20" id="Fjs-yN-xbn"/>
                                         <constraint firstItem="oYg-rg-sRX" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="GPe-zd-5ci"/>
-                                        <constraint firstItem="hZX-eZ-E0u" firstAttribute="leading" secondItem="oYg-rg-sRX" secondAttribute="trailing" constant="10" id="GsL-bZ-Shg"/>
+                                        <constraint firstItem="AmG-2j-Y75" firstAttribute="leading" secondItem="4wC-NG-1q2" secondAttribute="trailing" constant="10" id="IvR-if-0dK"/>
+                                        <constraint firstItem="hZX-eZ-E0u" firstAttribute="leading" secondItem="0cb-tT-6Se" secondAttribute="trailing" constant="20" id="KOC-jZ-Usi"/>
                                         <constraint firstAttribute="bottom" secondItem="4wC-NG-1q2" secondAttribute="bottom" constant="5" id="VtW-8E-Wln"/>
                                         <constraint firstAttribute="bottom" secondItem="0cb-tT-6Se" secondAttribute="bottom" constant="5" id="WlZ-vF-Hr6"/>
                                         <constraint firstItem="yuu-Ju-MKr" firstAttribute="leading" secondItem="oYg-rg-sRX" secondAttribute="trailing" constant="10" id="Y4S-hv-y1P"/>
@@ -330,7 +331,6 @@
                                         <constraint firstItem="0cb-tT-6Se" firstAttribute="leading" secondItem="AmG-2j-Y75" secondAttribute="trailing" constant="20" id="iAI-d3-joG"/>
                                         <constraint firstAttribute="trailing" secondItem="yuu-Ju-MKr" secondAttribute="trailing" constant="10" id="iF6-ia-hBT"/>
                                         <constraint firstAttribute="bottom" secondItem="oYg-rg-sRX" secondAttribute="bottom" constant="5" id="mW5-ze-raR"/>
-                                        <constraint firstItem="ad0-s7-tSM" firstAttribute="leading" secondItem="0cb-tT-6Se" secondAttribute="trailing" constant="20" id="pUr-10-jnu"/>
                                         <constraint firstAttribute="bottom" secondItem="ad0-s7-tSM" secondAttribute="bottom" constant="5" id="peC-1f-wPe"/>
                                         <constraint firstAttribute="bottom" secondItem="hZX-eZ-E0u" secondAttribute="bottom" constant="5" id="xIw-Sw-cwS"/>
                                         <constraint firstItem="oYg-rg-sRX" firstAttribute="leading" secondItem="Iet-JC-0rQ" secondAttribute="leading" constant="5" id="xwT-lV-EqG"/>
@@ -355,17 +355,6 @@
                         </connections>
                     </tableView>
                     <navigationItem key="navigationItem" id="QiI-QE-qqY">
-                        <segmentedControl key="titleView" hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="F62-D9-UTh">
-                            <rect key="frame" x="112.5" y="6" width="150" height="32"/>
-                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
-                            <segments>
-                                <segment title="鎴戠殑"/>
-                                <segment title="鍒嗕韩"/>
-                            </segments>
-                            <connections>
-                                <action selector="segmentControl:" destination="PUV-T9-WXJ" eventType="valueChanged" id="AUJ-pw-F6P"/>
-                            </connections>
-                        </segmentedControl>
                         <rightBarButtonItems>
                             <barButtonItem systemItem="add" id="yGh-cj-oPZ">
                                 <connections>
@@ -382,7 +371,6 @@
                     <connections>
                         <outlet property="addButton" destination="yGh-cj-oPZ" id="KX9-xN-pem"/>
                         <outlet property="logoutBtn" destination="5JV-V5-93l" id="mDS-mp-F4P"/>
-                        <outlet property="segmentedControl" destination="F62-D9-UTh" id="Ybb-pD-fvi"/>
                         <segue destination="uBF-Yq-Qo0" kind="push" identifier="go2LivePlay" id="X3Q-o5-p8V"/>
                         <segue destination="I6z-uV-dEU" kind="push" identifier="go2Playback" id="Qls-Y0-o2u"/>
                         <segue destination="MVz-Sq-jf5" kind="push" identifier="go2MessageList" id="Kgx-sc-mTL"/>
@@ -392,7 +380,7 @@
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="NKy-d7-m62" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="724" y="242"/>
+            <point key="canvasLocation" x="724" y="241.52923538230885"/>
         </scene>
         <!--Camera Table View Controller-->
         <scene sceneID="TjS-bX-rfT">
@@ -1196,14 +1184,14 @@
                                             <action selector="localButtonClicked:" destination="uBF-Yq-Qo0" eventType="touchUpInside" id="ghH-Hn-KkG"/>
                                         </connections>
                                     </button>
-                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WYB-ca-Ox6">
+                                    <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WYB-ca-Ox6">
                                         <rect key="frame" x="323" y="20" width="32" height="32"/>
                                         <state key="normal" image="cloud"/>
                                         <connections>
                                             <action selector="clickCloudBtn:" destination="uBF-Yq-Qo0" eventType="touchUpInside" id="Ft8-PW-PT5"/>
                                         </connections>
                                     </button>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="浜戝瓨鍌�" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wXb-RI-dLd">
+                                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="浜戝瓨鍌�" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wXb-RI-dLd">
                                         <rect key="frame" x="319" y="52" width="40" height="16"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                         <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -2037,10 +2025,11 @@
                         <subviews>
                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="璇疯緭鍏ヨ澶囧悕绉�" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="r1W-d8-Rg7">
                                 <rect key="frame" x="0.0" y="94" width="375" height="40"/>
-                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="40" id="NLX-OK-XZ7"/>
                                 </constraints>
+                                <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                 <textInputTraits key="textInputTraits"/>
                             </textField>
@@ -2483,9 +2472,10 @@
     <inferredMetricsTieBreakers>
         <segue reference="Qls-Y0-o2u"/>
         <segue reference="X3Q-o5-p8V"/>
-        <segue reference="q2I-Q5-CUY"/>
+        <segue reference="9Tu-UR-Cms"/>
         <segue reference="vdt-wN-aOY"/>
     </inferredMetricsTieBreakers>
+    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
     <resources>
         <image name="StreamStudio" width="24" height="24"/>
         <image name="StreamStudio-2" width="24" height="24"/>
diff --git a/Demo/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m b/Demo/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
index dd8051f..935f895 100644
--- a/Demo/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
+++ b/Demo/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
@@ -35,15 +35,21 @@
     }
     
     self.nameLabel.text = [NSString stringWithFormat:@"%@",deviceInfo.deviceName];
-    [self.cameraImageView sd_setImageWithURL:[NSURL URLWithString:deviceInfo.deviceCover] placeholderImageScale:nil];
+    //    self.cameraImageView.contentMode =  UIViewContentModeScaleAspectFit;
+    [self.cameraImageView sd_setImageWithURL:[NSURL URLWithString:deviceInfo.deviceCover] placeholderImage:[UIImage imageNamed:@"device_default"]];
 //    [EZOPENSDK capturePicture:cameraInfo.deviceSerial channelNo:cameraInfo.channelNo completion:^(NSString *url, NSError *error) {
 //        if(!error){
 //            [self.cameraImageView sd_setImageWithURL:[NSURL URLWithString:url]];
 //        }
 //    }];
+//    [EZOPENSDK cap]
+    
+    //2021-05-08 闅愯棌褰曞儚鎸夐挳
+    self.recordButton.hidden = YES;
     
     self.messageButton.hidden = NO;
     self.settingButton.hidden = NO;
+    
     if (self.isShared)
     {
         self.messageButton.hidden = YES;
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo.xcodeproj/project.pbxproj b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo.xcodeproj/project.pbxproj
index 4cb039c..a00534f 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo.xcodeproj/project.pbxproj
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo.xcodeproj/project.pbxproj
@@ -144,6 +144,8 @@
 		B95004F725B929EF002D3C58 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B95004F625B929EF002D3C58 /* Launch Screen.storyboard */; };
 		B96C125625E8C5EA00B69941 /* EZSDK.m in Sources */ = {isa = PBXBuildFile; fileRef = B96C125525E8C5EA00B69941 /* EZSDK.m */; };
 		B96C126725E8F64800B69941 /* EZHttpUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B96C126625E8F64800B69941 /* EZHttpUtil.m */; };
+		B9E6208D26969E170054E443 /* NSObject+YYModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B9E6208A26969E170054E443 /* NSObject+YYModel.m */; };
+		B9E6208E26969E170054E443 /* YYClassInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = B9E6208B26969E170054E443 /* YYClassInfo.m */; };
 		B9EA4E3825C7E7AB000FFDA2 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = B9EA4E0725C7E7AB000FFDA2 /* LICENSE */; };
 		B9EA4E3925C7E7AB000FFDA2 /* UIScrollView+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = B9EA4E0925C7E7AB000FFDA2 /* UIScrollView+MJRefresh.m */; };
 		B9EA4E3A25C7E7AB000FFDA2 /* MJRefreshConst.m in Sources */ = {isa = PBXBuildFile; fileRef = B9EA4E0A25C7E7AB000FFDA2 /* MJRefreshConst.m */; };
@@ -573,6 +575,11 @@
 		B96C125525E8C5EA00B69941 /* EZSDK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZSDK.m; sourceTree = "<group>"; };
 		B96C126525E8F64800B69941 /* EZHttpUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZHttpUtil.h; sourceTree = "<group>"; };
 		B96C126625E8F64800B69941 /* EZHttpUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZHttpUtil.m; sourceTree = "<group>"; };
+		B9E6208826969E170054E443 /* YYClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYClassInfo.h; sourceTree = "<group>"; };
+		B9E6208926969E170054E443 /* YYModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYModel.h; sourceTree = "<group>"; };
+		B9E6208A26969E170054E443 /* NSObject+YYModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+YYModel.m"; sourceTree = "<group>"; };
+		B9E6208B26969E170054E443 /* YYClassInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYClassInfo.m; sourceTree = "<group>"; };
+		B9E6208C26969E170054E443 /* NSObject+YYModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+YYModel.h"; sourceTree = "<group>"; };
 		B9EA4E0725C7E7AB000FFDA2 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
 		B9EA4E0925C7E7AB000FFDA2 /* UIScrollView+MJRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+MJRefresh.m"; sourceTree = "<group>"; };
 		B9EA4E0A25C7E7AB000FFDA2 /* MJRefreshConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJRefreshConst.m; sourceTree = "<group>"; };
@@ -892,6 +899,7 @@
 		0D8CF3A91BDF516700A50266 /* Venders */ = {
 			isa = PBXGroup;
 			children = (
+				B9E6208726969E170054E443 /* YYModel */,
 				B9EA4E0625C7E7AA000FFDA2 /* MJRefresh */,
 				C4A41D7C23D6E4DC00D59722 /* Toast */,
 				0D9ACAD31C7EE4D100B4DE97 /* UIKit+AFNetworking */,
@@ -1327,6 +1335,18 @@
 			name = Category;
 			sourceTree = "<group>";
 		};
+		B9E6208726969E170054E443 /* YYModel */ = {
+			isa = PBXGroup;
+			children = (
+				B9E6208826969E170054E443 /* YYClassInfo.h */,
+				B9E6208926969E170054E443 /* YYModel.h */,
+				B9E6208A26969E170054E443 /* NSObject+YYModel.m */,
+				B9E6208B26969E170054E443 /* YYClassInfo.m */,
+				B9E6208C26969E170054E443 /* NSObject+YYModel.h */,
+			);
+			path = YYModel;
+			sourceTree = "<group>";
+		};
 		B9EA4E0625C7E7AA000FFDA2 /* MJRefresh */ = {
 			isa = PBXGroup;
 			children = (
@@ -1735,12 +1755,14 @@
 				0D77A3301BE0F2E800B4AD0A /* EZInputSerialViewController.m in Sources */,
 				0DCE0C421BE227F6000EA68A /* MBProgressHUD.m in Sources */,
 				0DCE0C321BE2279F000EA68A /* SDWebImageCompat.m in Sources */,
+				B9E6208D26969E170054E443 /* NSObject+YYModel.m in Sources */,
 				0D9ACAEB1C7EE4D100B4DE97 /* UIProgressView+AFNetworking.m in Sources */,
 				0D8CF4DA1BDF898800A50266 /* UITableView+FDIndexPathHeightCache.m in Sources */,
 				0DCE0C081BE22761000EA68A /* UILabel+DDKit.m in Sources */,
 				0D5015121BF8B77500F13269 /* UIImage+MWPhotoBrowser.m in Sources */,
 				0D90A06B1CABC6A100E78C64 /* EZPlayDemoViewController.m in Sources */,
 				0DCE0C3C1BE2279F000EA68A /* UIImageView+HighlightedWebCache.m in Sources */,
+				B9E6208E26969E170054E443 /* YYClassInfo.m in Sources */,
 				B9EA4E3925C7E7AB000FFDA2 /* UIScrollView+MJRefresh.m in Sources */,
 				B96C125625E8C5EA00B69941 /* EZSDK.m in Sources */,
 				0D77A3361BE0F38D00B4AD0A /* EZDeviceResultViewController.m in Sources */,
@@ -1978,7 +2000,7 @@
 				MARKETING_VERSION = 4.15.0;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "-ObjC";
-				PRODUCT_BUNDLE_IDENTIFIER = com.hdl.on;
+				PRODUCT_BUNDLE_IDENTIFIER = com.hdl.on2;
 				PRODUCT_NAME = EZOpenSDK;
 				PROVISIONING_PROFILE = "";
 				PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/AppDelegate.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/AppDelegate.m
index a698773..024b58c 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/AppDelegate.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/AppDelegate.m
@@ -30,9 +30,9 @@
     
 //    [EZOPENSDK initLibWithAppKey:@"0311c3f70a854aacb5a099f2bfbef986"];
     //ON+
-//    [EZOPENSDK initLibWithAppKey:@"1aa98a90489b4838b966b57018b4b04b"];
-    //home
-    [EZOPENSDK initLibWithAppKey:@"89f6219d561441f5b664c7475698841e"];
+    [EZOPENSDK initLibWithAppKey:@"1aa98a90489b4838b966b57018b4b04b"];
+//    //home
+//    [EZOPENSDK initLibWithAppKey:@"89f6219d561441f5b664c7475698841e"];
     
 //    NSLog(@"LanguageIsChinese :%s", LanguageIsChinese ? "YES":"NO");
 //    NSLog(@"NSStringFromClass :%@", NSStringFromClass(EZOPENSDK));
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/AddDevice.storyboard b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/AddDevice.storyboard
index 284eeed..947d393 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/AddDevice.storyboard
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/AddDevice.storyboard
@@ -686,12 +686,24 @@
                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q0X-wy-A5B">
                                 <rect key="frame" x="47.5" y="362" width="311.5" height="40"/>
                                 <attributedString key="attributedText">
-                                    <fragment content="杩斿洖demo锛岀瓑寰呬笌璁惧杩炴帴锛屾垚鍔熷悗鑷姩杩涘叆涓嬩竴姝ユ搷浣溿��">
+                                    <fragment content="杩斿洖">
+                                        <attributes>
+                                            <font key="NSFont" size="14" name=".PingFangSC-Regular"/>
+                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" minimumLineHeight="20" tighteningFactorForTruncation="0.0"/>
+                                        </attributes>
+                                    </fragment>
+                                    <fragment content="APP">
                                         <attributes>
                                             <font key="NSFont" metaFont="system" size="14"/>
                                             <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" minimumLineHeight="20" tighteningFactorForTruncation="0.0"/>
                                         </attributes>
                                     </fragment>
+                                    <fragment content="锛岀瓑寰呬笌璁惧杩炴帴锛屾垚鍔熷悗鑷姩杩涘叆涓嬩竴姝ユ搷浣溿��">
+                                        <attributes>
+                                            <font key="NSFont" size="14" name=".PingFangSC-Regular"/>
+                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" minimumLineHeight="20" tighteningFactorForTruncation="0.0"/>
+                                        </attributes>
+                                    </fragment>
                                 </attributedString>
                                 <nil key="highlightedColor"/>
                             </label>
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
index 0db5c3a..ac982a3 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Base.lproj/EZMain.storyboard
@@ -244,7 +244,7 @@
                                             <nil key="highlightedColor"/>
                                         </label>
                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hZX-eZ-E0u">
-                                            <rect key="frame" x="127" y="29" width="39" height="39"/>
+                                            <rect key="frame" x="245" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="4QQ-tz-dPq"/>
                                                 <constraint firstAttribute="height" constant="39" id="RuZ-Pc-8zE"/>
@@ -258,7 +258,7 @@
                                             </connections>
                                         </button>
                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AmG-2j-Y75">
-                                            <rect key="frame" x="186" y="29" width="39" height="39"/>
+                                            <rect key="frame" x="127" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="Q42-XD-P1b"/>
                                                 <constraint firstAttribute="height" constant="39" id="iDX-Vm-hmw"/>
@@ -288,7 +288,7 @@
                                             </constraints>
                                         </imageView>
                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0cb-tT-6Se">
-                                            <rect key="frame" x="245" y="29" width="39" height="39"/>
+                                            <rect key="frame" x="186" y="29" width="39" height="39"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="39" id="Mps-h7-nX0"/>
                                                 <constraint firstAttribute="height" constant="39" id="hNG-1A-X3w"/>
@@ -316,12 +316,13 @@
                                     <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
                                     <constraints>
                                         <constraint firstItem="4wC-NG-1q2" firstAttribute="leading" secondItem="Iet-JC-0rQ" secondAttribute="leading" constant="5" id="2lM-8U-Coj"/>
-                                        <constraint firstItem="AmG-2j-Y75" firstAttribute="leading" secondItem="hZX-eZ-E0u" secondAttribute="trailing" constant="20" id="3AL-W4-tN5"/>
                                         <constraint firstAttribute="bottom" secondItem="AmG-2j-Y75" secondAttribute="bottom" constant="5" id="4hD-YQ-TQt"/>
                                         <constraint firstItem="4wC-NG-1q2" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="CpW-TJ-kmv"/>
                                         <constraint firstItem="yuu-Ju-MKr" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="Exf-xl-NwN"/>
+                                        <constraint firstItem="ad0-s7-tSM" firstAttribute="leading" secondItem="hZX-eZ-E0u" secondAttribute="trailing" constant="20" id="Fjs-yN-xbn"/>
                                         <constraint firstItem="oYg-rg-sRX" firstAttribute="top" secondItem="Iet-JC-0rQ" secondAttribute="top" constant="5" id="GPe-zd-5ci"/>
-                                        <constraint firstItem="hZX-eZ-E0u" firstAttribute="leading" secondItem="oYg-rg-sRX" secondAttribute="trailing" constant="10" id="GsL-bZ-Shg"/>
+                                        <constraint firstItem="AmG-2j-Y75" firstAttribute="leading" secondItem="4wC-NG-1q2" secondAttribute="trailing" constant="10" id="IvR-if-0dK"/>
+                                        <constraint firstItem="hZX-eZ-E0u" firstAttribute="leading" secondItem="0cb-tT-6Se" secondAttribute="trailing" constant="20" id="KOC-jZ-Usi"/>
                                         <constraint firstAttribute="bottom" secondItem="4wC-NG-1q2" secondAttribute="bottom" constant="5" id="VtW-8E-Wln"/>
                                         <constraint firstAttribute="bottom" secondItem="0cb-tT-6Se" secondAttribute="bottom" constant="5" id="WlZ-vF-Hr6"/>
                                         <constraint firstItem="yuu-Ju-MKr" firstAttribute="leading" secondItem="oYg-rg-sRX" secondAttribute="trailing" constant="10" id="Y4S-hv-y1P"/>
@@ -330,7 +331,6 @@
                                         <constraint firstItem="0cb-tT-6Se" firstAttribute="leading" secondItem="AmG-2j-Y75" secondAttribute="trailing" constant="20" id="iAI-d3-joG"/>
                                         <constraint firstAttribute="trailing" secondItem="yuu-Ju-MKr" secondAttribute="trailing" constant="10" id="iF6-ia-hBT"/>
                                         <constraint firstAttribute="bottom" secondItem="oYg-rg-sRX" secondAttribute="bottom" constant="5" id="mW5-ze-raR"/>
-                                        <constraint firstItem="ad0-s7-tSM" firstAttribute="leading" secondItem="0cb-tT-6Se" secondAttribute="trailing" constant="20" id="pUr-10-jnu"/>
                                         <constraint firstAttribute="bottom" secondItem="ad0-s7-tSM" secondAttribute="bottom" constant="5" id="peC-1f-wPe"/>
                                         <constraint firstAttribute="bottom" secondItem="hZX-eZ-E0u" secondAttribute="bottom" constant="5" id="xIw-Sw-cwS"/>
                                         <constraint firstItem="oYg-rg-sRX" firstAttribute="leading" secondItem="Iet-JC-0rQ" secondAttribute="leading" constant="5" id="xwT-lV-EqG"/>
@@ -380,7 +380,7 @@
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="NKy-d7-m62" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="724" y="242"/>
+            <point key="canvasLocation" x="724" y="241.52923538230885"/>
         </scene>
         <!--Camera Table View Controller-->
         <scene sceneID="TjS-bX-rfT">
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZHttpUtil.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZHttpUtil.m
index 29b7426..6c2236e 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZHttpUtil.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZHttpUtil.m
@@ -13,9 +13,9 @@
 
 #define TestRequestHttpsHost @"https://test-gz.hdlcontrol.com"
 #pragma mark API
-#define API_POST_EZ_AddDevice @"/home-wisdom/platform/childAddDevice"
-#define API_POST_EZ_GetChildToken @"/home-wisdom/platform/childToken"
-#define API_POST_EZ_ChildDelDevice @"/home-wisdom/platform/childDelDevice"
+#define API_POST_EZ_AddDevice @"/home-wisdom/platform/yingshi/child/addDevice"
+#define API_POST_EZ_GetChildToken @"/home-wisdom/platform/yingshi/child/token"
+#define API_POST_EZ_ChildDelDevice @"/home-wisdom/platform/yingshi/child/deleteDevice"
 #define API_POST_EZ_RefreshToken @"/smart-footstone/member/oauth/login"
 
 
@@ -51,13 +51,15 @@
     //2.璁剧疆璇锋眰鍙傛暟
     NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
     [parameters setValue: [NSString stringWithFormat:@"%d", [GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
     parameters = [self GetSignRequestDictionary:parameters];
     
     [self requestHttpsPost:API_POST_EZ_GetChildToken parameters:parameters completion:^(ResponseData *responseData) {
         if (block) {
             NSString * token = @"";
             if(responseData.success){
-                token = responseData.data[@"accessToken"];
+//                token = responseData.data[@"accessToken"];
+                token = [NSString stringWithFormat:@"%@",responseData.data];
             }
             block(token);
         }
@@ -84,9 +86,11 @@
     [parameters setValue:deviceSerial forKey:@"deviceSerial"];
     [parameters setValue:verifyCode forKey:@"validateCode"];
     [parameters setValue: [NSString stringWithFormat:@"%d",[GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
+    
     parameters = [self GetSignRequestDictionary:parameters];
     
-   [self requestHttpsPost:API_POST_EZ_AddDevice parameters:parameters completion:^(ResponseData *responseData) {
+    [self requestHttpsPost:API_POST_EZ_AddDevice parameters:parameters completion:^(ResponseData *responseData) {
         if (completion) {
             completion (responseData);
         }
@@ -108,6 +112,8 @@
     NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
     [parameters setValue:deviceSerial forKey:@"deviceSerial"];
     [parameters setValue: [NSString stringWithFormat:@"%d",[GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
+    
     parameters = [self GetSignRequestDictionary:parameters];
     
     [self requestHttpsPost:API_POST_EZ_ChildDelDevice parameters:parameters completion:^(ResponseData *responseData) {
@@ -251,7 +257,8 @@
     NSString *newString = @"";
     for(NSString *key in sortKeyArray){
         if(params[key] != NULL){
-            NSString *valueStr = params[key];
+            //Key瀵瑰簲鐨剉alue寮鸿浆涓篘SString
+            NSString *valueStr = [NSString stringWithFormat:@"%@",[params objectForKey:key]];
             //妫�娴嬪綋鍓嶅弬鏁版槸鍚﹂渶瑕佸弬涓庢牎楠�
             if([self IfValueNeedSign:valueStr]){
                 newString = [newString stringByAppendingString:[NSString stringWithFormat:@"%@=%@&", key,valueStr]];
@@ -311,7 +318,10 @@
     if (( [self stringIsNullOrEmpty:valueStr])//鍒ょ┖瀛楃
         || ([[valueStr substringToIndex:1] isEqual:@"{"])//鍒ゆ柇鏄惁涓哄璞�
         || ([[valueStr substringToIndex:1] isEqual:@"["])//鍒ゆ柇鏄惁涓烘暟缁�
+        || ([[valueStr substringToIndex:1] isEqual:@"("])//鍒ゆ柇鏄惁涓烘暟缁�
         ) {
+        
+//        HDLSDKLog(@"涓嶆牎楠�: %@",valueStr);
         return false;
     }
     return true;
@@ -319,3 +329,9 @@
 
 
 @end
+
+
+#pragma mark - 淇敼璁板綍
+//2021-07-07
+//V1.1.3
+//1.鏇挎崲涓烘柊鎺ュ彛锛屾牴鎹甴omeId娉ㄥ唽钀ょ煶瀛愯处鍙锋柟妗堛��
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.h b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.h
index d9b3fe5..9325728 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.h
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.h
@@ -6,7 +6,7 @@
 //
 
 #import <Foundation/Foundation.h>
-
+#import "EZDeviceInfo.h"
 
 @interface EZSDK : NSObject
 /**
@@ -21,11 +21,11 @@
 /**
  璁剧疆HDLSDK鐨刟ccessToken
  */
-+(void)setHDlAccessToken:(NSString *) accessToken refreshToken:(NSString *) refreshToken;
++(void)setHDlAccessToken:(NSString *)accessToken refreshToken:(NSString *) refreshToken;
 /**
  璁剧疆SDK鐨勬渤涓滄帴鍙g殑requestHttpsHost鍜屽钩鍙� 鏍囪瘑锛�1.on+(榛樿) 2.evoyo
  */
-+(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int) platform;
++(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int)platform homeId:(NSString *)homeId;
 
 /**
  鐩存帴璺宠浆鍒拌悿鐭虫憚鍍忓ご鍒楄〃
@@ -38,14 +38,17 @@
 /**
  鏌ョ湅瑙嗛鐩戞帶鐩存挱
  */
-+(void)Play:(NSObject*)deviceInfo;
++(void)Play:(EZDeviceInfo*)deviceInfo;
+/// 鎸囧畾搴忓垪鍙� 鏌ョ湅瑙嗛鐩戞帶鐩存挱
+/// @param deviceSerial 搴忓垪鍙�
++(void)PlayWithDeviceSerial:(NSString *)deviceSerial;
 /**
  鎵撳紑鎽勫儚澶磋缃〉闈�
  */
-+(void)setting:(NSObject*)deviceInfo;
++(void)setting:(EZDeviceInfo*)deviceInfo;
 /**
  鍥炴斁鎾斁鍘嗗彶
  */
-+(void)playBackVideo:(NSObject*)deviceInfo;
++(void)playBackVideo:(EZDeviceInfo*)deviceInfo;
 
 @end
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.m
index d283890..cfb414f 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/EZSDK.m
@@ -25,13 +25,15 @@
 
 @implementation EZSDK
 
+static BOOL isHavelibInit=NO;
+
 /**
  鍒濆鍖朣DK
  浼犲叆鍥藉唴鐗坘ey 鍜屾捣澶栫増globalAppKey
  */
 + (BOOL)initLibWithAppKey:(NSString *)appKey globalAppKey:(NSString *)globalAppKey
 {
-    static BOOL isHavelibInit=NO;
+  
     if (!isHavelibInit) {
         //        isHavelibInit=YES;
         //        NSLog(@"绗竴娆″垵濮嬪寲钀ょ煶搴�");
@@ -72,9 +74,10 @@
 /**
  璁剧疆SDK鐨勬渤涓滄帴鍙g殑requestHttpsHost鍜屽钩鍙� 鏍囪瘑锛�1.on+(榛樿) 2.evoyo
  */
-+(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int) platform{
++(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int)platform homeId:(NSString *)homeId{
     [[GlobalKit shareKit] setGlobalRequestHttpsHost:requestHttpsHost];
     [[GlobalKit shareKit] setHdlPlatform:platform];
+    [[GlobalKit shareKit] setHdlHomeId:homeId];
 }
 
 //鑾峰彇褰撳墠灞忓箷鏄剧ず鐨剉iewcontroller   (杩欓噷闈㈣幏鍙栫殑鐩稿綋浜巖ootViewController)
@@ -136,22 +139,40 @@
 /**
  鏌ョ湅瑙嗛鐩戞帶鐩存挱
  */
-+(void)Play:(NSObject*)deviceInfo
++(void)Play:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *addDeviceStoryBoard = [UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZLivePlayViewController *rootViewController = [addDeviceStoryBoard instantiateViewControllerWithIdentifier:@"EZLivePlayViewController"];
     //        NSLog(@"play--iphone--rootViewController");
     rootViewController.deviceInfo=(EZDeviceInfo *)deviceInfo;
     NSLog(@"play--iphone--deviceName -%@",rootViewController.deviceInfo.deviceName);
-    //        rootViewController.cameraIndex=0;
+//            rootViewController.cameraIndex=0;
     [[self getCurrentVC] setNavigationBarHidden:NO];
     [[self getCurrentVC] pushViewController:rootViewController animated:YES];
+    
+    
+}
+
+/// 鎸囧畾搴忓垪鍙锋挱鏀�
+/// @param deviceSerial 搴忓垪鍙�
++(void)PlayWithDeviceSerial:(NSString *)deviceSerial{
+    //鑾峰彇璁惧鍒楄〃鎺ュ彛
+    [EZOpenSDK getDeviceInfo:deviceSerial completion:^(EZDeviceInfo *deviceInfo, NSError *error) {
+        if(error)
+        {
+            NSLog(@"EZ 鏌ヨ璁惧淇℃伅澶辫触");
+            return;
+        }
+        if (deviceInfo) {
+            [self Play:deviceInfo];
+        }
+    }];
 }
 
 /**
  鎵撳紑鎽勫儚澶磋缃〉闈�
  */
-+(void)setting:(NSObject*)deviceInfo
++(void)setting:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *settingStoryBoard=[UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZSettingViewController *settingVC=[settingStoryBoard instantiateViewControllerWithIdentifier:@"EZSettingViewController"];
@@ -163,7 +184,7 @@
 /**
  鍥炴斁鎾斁鍘嗗彶
  */
-+(void)playBackVideo:(NSObject*)deviceInfo
++(void)playBackVideo:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *playBackStoryBoard=[UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZPlaybackViewController *playBackVC=[playBackStoryBoard instantiateViewControllerWithIdentifier:@"EZPlaybackViewController"];
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.h b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.h
index 1ede585..d8917f4 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.h
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.h
@@ -22,6 +22,7 @@
 @property (nonatomic, copy) NSString *GlobalRequestHttpsHost;
 @property (nonatomic, copy) NSString *hdlAccessToken;
 @property (nonatomic, copy) NSString *hdlRefreshToken;
+@property (nonatomic, copy) NSString *hdlHomeId;
 
 @property (nonatomic, copy) NSString *accessToken;
 @property (nonatomic, copy) NSString *deviceSerialNo;  //璁惧搴忓垪鍙�
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.m
index 4a06059..e26e622 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Global/GlobalKit.m
@@ -45,6 +45,7 @@
     _accessToken = accessToken;
     [[NSUserDefaults standardUserDefaults] setObject:accessToken?:@"" forKey:EZOpenSDKAccessToken];
     [[NSUserDefaults standardUserDefaults] synchronize];
+    [EZOPENSDK setAccessToken:[GlobalKit shareKit].accessToken];
 }
 
 - (void)setHdlAccessToken:(NSString *)hdlAccessToken
@@ -66,7 +67,7 @@
     _GlobalRequestHttpsHost = GlobalRequestHttpsHost;
 }
 
-- (void)sethdlPlatform:(int )hdlPlatform
+- (void)sethdlPlatform:(int)hdlPlatform
 {
     _hdlPlatform = hdlPlatform;
 }
@@ -74,7 +75,7 @@
 - (void)clearSession
 {
     _accessToken = nil;
-    _hdlRefreshToken = nil;
+    _hdlAccessToken = nil;
     _hdlRefreshToken = nil;
     [[NSUserDefaults standardUserDefaults] removeObjectForKey:EZOpenSDKAccessToken];
     [[NSUserDefaults standardUserDefaults] synchronize];
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
index 935f895..b3c8980 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/TableViewCells/DeviceListCell.m
@@ -44,8 +44,8 @@
 //    }];
 //    [EZOPENSDK cap]
     
-    //2021-05-08 闅愯棌褰曞儚鎸夐挳
-    self.recordButton.hidden = YES;
+//    //2021-05-08 闅愯棌褰曞儚鎸夐挳
+//    self.recordButton.hidden = YES;
     
     self.messageButton.hidden = NO;
     self.settingButton.hidden = NO;
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.h b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.h
new file mode 100644
index 0000000..73f62ec
--- /dev/null
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.h
@@ -0,0 +1,440 @@
+//
+//  NSObject+YYModel.h
+//  YYModel <https://github.com/ibireme/YYModel>
+//
+//  Created by ibireme on 15/5/10.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provide some data-model method:
+ 
+ * Convert json to any object, or convert any object to json.
+ * Set object properties with a key-value dictionary (like KVC).
+ * Implementations of `NSCoding`, `NSCopying`, `-hash` and `-isEqual:`.
+ 
+ See `YYModel` protocol for custom methods.
+ 
+ 
+ Sample Code:
+    
+     ********************** json convertor *********************
+ @code
+     @interface YYAuthor : NSObject
+     @property (nonatomic, strong) NSString *name;
+     @property (nonatomic, assign) NSDate *birthday;
+     @end
+     @implementation YYAuthor
+     @end
+ 
+     @interface YYBook : NSObject
+     @property (nonatomic, copy) NSString *name;
+     @property (nonatomic, assign) NSUInteger pages;
+     @property (nonatomic, strong) YYAuthor *author;
+     @end
+     @implementation YYBook
+     @end
+    
+     int main() {
+         // create model from json
+         YYBook *book = [YYBook yy_modelWithJSON:@"{\"name\": \"Harry Potter\", \"pages\": 256, \"author\": {\"name\": \"J.K.Rowling\", \"birthday\": \"1965-07-31\" }}"];
+ 
+         // convert model to json
+         NSString *json = [book yy_modelToJSONString];
+         // {"author":{"name":"J.K.Rowling","birthday":"1965-07-31T00:00:00+0000"},"name":"Harry Potter","pages":256}
+     }
+ @endcode
+ 
+     ********************** Coding/Copying/hash/equal *********************
+ @code
+     @interface YYShadow :NSObject <NSCoding, NSCopying>
+     @property (nonatomic, copy) NSString *name;
+     @property (nonatomic, assign) CGSize size;
+     @end
+ 
+     @implementation YYShadow
+     - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }
+     - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self yy_modelInitWithCoder:aDecoder]; }
+     - (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; }
+     - (NSUInteger)hash { return [self yy_modelHash]; }
+     - (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }
+     @end
+ @endcode
+ 
+ */
+@interface NSObject (YYModel)
+
+/**
+ Creates and returns a new instance of the receiver from a json.
+ This method is thread-safe.
+ 
+ @param json  A json object in `NSDictionary`, `NSString` or `NSData`.
+ 
+ @return A new instance created from the json, or nil if an error occurs.
+ */
++ (nullable instancetype)yy_modelWithJSON:(id)json;
+
+/**
+ Creates and returns a new instance of the receiver from a key-value dictionary.
+ This method is thread-safe.
+ 
+ @param dictionary  A key-value dictionary mapped to the instance's properties.
+ Any invalid key-value pair in dictionary will be ignored.
+ 
+ @return A new instance created from the dictionary, or nil if an error occurs.
+ 
+ @discussion The key in `dictionary` will mapped to the reciever's property name,
+ and the value will set to the property. If the value's type does not match the
+ property, this method will try to convert the value based on these rules:
+ 
+     `NSString` or `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
+     `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
+     `NSString` -> NSURL.
+     `NSValue` -> struct or union, such as CGRect, CGSize, ...
+     `NSString` -> SEL, Class.
+ */
++ (nullable instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary;
+
+/**
+ Set the receiver's properties with a json object.
+ 
+ @discussion Any invalid data in json will be ignored.
+ 
+ @param json  A json object of `NSDictionary`, `NSString` or `NSData`, mapped to the
+ receiver's properties.
+ 
+ @return Whether succeed.
+ */
+- (BOOL)yy_modelSetWithJSON:(id)json;
+
+/**
+ Set the receiver's properties with a key-value dictionary.
+ 
+ @param dic  A key-value dictionary mapped to the receiver's properties.
+ Any invalid key-value pair in dictionary will be ignored.
+ 
+ @discussion The key in `dictionary` will mapped to the reciever's property name,
+ and the value will set to the property. If the value's type doesn't match the
+ property, this method will try to convert the value based on these rules:
+ 
+     `NSString`, `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
+     `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
+     `NSString` -> NSURL.
+     `NSValue` -> struct or union, such as CGRect, CGSize, ...
+     `NSString` -> SEL, Class.
+ 
+ @return Whether succeed.
+ */
+- (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic;
+
+/**
+ Generate a json object from the receiver's properties.
+ 
+ @return A json object in `NSDictionary` or `NSArray`, or nil if an error occurs.
+ See [NSJSONSerialization isValidJSONObject] for more information.
+ 
+ @discussion Any of the invalid property is ignored.
+ If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it just convert
+ the inner object to json object.
+ */
+- (nullable id)yy_modelToJSONObject;
+
+/**
+ Generate a json string's data from the receiver's properties.
+ 
+ @return A json string's data, or nil if an error occurs.
+ 
+ @discussion Any of the invalid property is ignored.
+ If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the 
+ inner object to json string.
+ */
+- (nullable NSData *)yy_modelToJSONData;
+
+/**
+ Generate a json string from the receiver's properties.
+ 
+ @return A json string, or nil if an error occurs.
+ 
+ @discussion Any of the invalid property is ignored.
+ If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the 
+ inner object to json string.
+ */
+- (nullable NSString *)yy_modelToJSONString;
+
+/**
+ Copy a instance with the receiver's properties.
+ 
+ @return A copied instance, or nil if an error occurs.
+ */
+- (nullable id)yy_modelCopy;
+
+/**
+ Encode the receiver's properties to a coder.
+ 
+ @param aCoder  An archiver object.
+ */
+- (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder;
+
+/**
+ Decode the receiver's properties from a decoder.
+ 
+ @param aDecoder  An archiver object.
+ 
+ @return self
+ */
+- (id)yy_modelInitWithCoder:(NSCoder *)aDecoder;
+
+/**
+ Get a hash code with the receiver's properties.
+ 
+ @return Hash code.
+ */
+- (NSUInteger)yy_modelHash;
+
+/**
+ Compares the receiver with another object for equality, based on properties.
+ 
+ @param model  Another object.
+ 
+ @return `YES` if the reciever is equal to the object, otherwise `NO`.
+ */
+- (BOOL)yy_modelIsEqual:(id)model;
+
+/**
+ Description method for debugging purposes based on properties.
+ 
+ @return A string that describes the contents of the receiver.
+ */
+- (NSString *)yy_modelDescription;
+
+@end
+
+
+
+/**
+ Provide some data-model method for NSArray.
+ */
+@interface NSArray (YYModel)
+
+/**
+ Creates and returns an array from a json-array.
+ This method is thread-safe.
+ 
+ @param cls  The instance's class in array.
+ @param json  A json array of `NSArray`, `NSString` or `NSData`.
+              Example: [{"name":"Mary"},{name:"Joe"}]
+ 
+ @return A array, or nil if an error occurs.
+ */
++ (nullable NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json;
+
+@end
+
+
+
+/**
+ Provide some data-model method for NSDictionary.
+ */
+@interface NSDictionary (YYModel)
+
+/**
+ Creates and returns a dictionary from a json.
+ This method is thread-safe.
+ 
+ @param cls  The value instance's class in dictionary.
+ @param json  A json dictionary of `NSDictionary`, `NSString` or `NSData`.
+              Example: {"user1":{"name","Mary"}, "user2": {name:"Joe"}}
+ 
+ @return A dictionary, or nil if an error occurs.
+ */
++ (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;
+@end
+
+
+
+/**
+ If the default model transform does not fit to your model class, implement one or
+ more method in this protocol to change the default key-value transform process.
+ There's no need to add '<YYModel>' to your class header.
+ */
+@protocol YYModel <NSObject>
+@optional
+
+/**
+ Custom property mapper.
+ 
+ @discussion If the key in JSON/Dictionary does not match to the model's property name,
+ implements this method and returns the additional mapper.
+ 
+ Example:
+    
+    json: 
+        {
+            "n":"Harry Pottery",
+            "p": 256,
+            "ext" : {
+                "desc" : "A book written by J.K.Rowling."
+            },
+            "ID" : 100010
+        }
+ 
+    model:
+    @code
+        @interface YYBook : NSObject
+        @property NSString *name;
+        @property NSInteger page;
+        @property NSString *desc;
+        @property NSString *bookID;
+        @end
+        
+        @implementation YYBook
+        + (NSDictionary *)modelCustomPropertyMapper {
+            return @{@"name"  : @"n",
+                     @"page"  : @"p",
+                     @"desc"  : @"ext.desc",
+                     @"bookID": @[@"id", @"ID", @"book_id"]};
+        }
+        @end
+     @endcode
+ 
+ @return A custom mapper for properties.
+ */
++ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
+
+/**
+ The generic class mapper for container properties.
+ 
+ @discussion If the property is a container object, such as NSArray/NSSet/NSDictionary,
+ implements this method and returns a property->class mapper, tells which kind of 
+ object will be add to the array/set/dictionary.
+ 
+  Example:
+  @code
+        @class YYShadow, YYBorder, YYAttachment;
+ 
+        @interface YYAttributes
+        @property NSString *name;
+        @property NSArray *shadows;
+        @property NSSet *borders;
+        @property NSDictionary *attachments;
+        @end
+ 
+        @implementation YYAttributes
+        + (NSDictionary *)modelContainerPropertyGenericClass {
+            return @{@"shadows" : [YYShadow class],
+                     @"borders" : YYBorder.class,
+                     @"attachments" : @"YYAttachment" };
+        }
+        @end
+  @endcode
+ 
+ @return A class mapper.
+ */
++ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
+
+/**
+ If you need to create instances of different classes during json->object transform,
+ use the method to choose custom class based on dictionary data.
+ 
+ @discussion If the model implements this method, it will be called to determine resulting class
+ during `+modelWithJSON:`, `+modelWithDictionary:`, conveting object of properties of parent objects 
+ (both singular and containers via `+modelContainerPropertyGenericClass`).
+ 
+ Example:
+ @code
+        @class YYCircle, YYRectangle, YYLine;
+ 
+        @implementation YYShape
+
+        + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
+            if (dictionary[@"radius"] != nil) {
+                return [YYCircle class];
+            } else if (dictionary[@"width"] != nil) {
+                return [YYRectangle class];
+            } else if (dictionary[@"y2"] != nil) {
+                return [YYLine class];
+            } else {
+                return [self class];
+            }
+        }
+
+        @end
+ @endcode
+
+ @param dictionary The json/kv dictionary.
+ 
+ @return Class to create from this dictionary, `nil` to use current class.
+
+ */
++ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;
+
+/**
+ All the properties in blacklist will be ignored in model transform process.
+ Returns nil to ignore this feature.
+ 
+ @return An array of property's name.
+ */
++ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
+
+/**
+ If a property is not in the whitelist, it will be ignored in model transform process.
+ Returns nil to ignore this feature.
+ 
+ @return An array of property's name.
+ */
++ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
+
+/**
+ This method's behavior is similar to `- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;`, 
+ but be called before the model transform.
+ 
+ @discussion If the model implements this method, it will be called before
+ `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
+ If this method returns nil, the transform process will ignore this model.
+ 
+ @param dic  The json/kv dictionary.
+ 
+ @return Returns the modified dictionary, or nil to ignore this model.
+ */
+- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;
+
+/**
+ If the default json-to-model transform does not fit to your model object, implement
+ this method to do additional process. You can also use this method to validate the 
+ model's properties.
+ 
+ @discussion If the model implements this method, it will be called at the end of
+ `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
+ If this method returns NO, the transform process will ignore this model.
+ 
+ @param dic  The json/kv dictionary.
+ 
+ @return Returns YES if the model is valid, or NO to ignore this model.
+ */
+- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
+
+/**
+ If the default model-to-json transform does not fit to your model class, implement
+ this method to do additional process. You can also use this method to validate the
+ json dictionary.
+ 
+ @discussion If the model implements this method, it will be called at the end of
+ `-modelToJSONObject` and `-modelToJSONString`.
+ If this method returns NO, the transform process will ignore this json dictionary.
+ 
+ @param dic  The json dictionary.
+ 
+ @return Returns YES if the model is valid, or NO to ignore this model.
+ */
+- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.m
new file mode 100644
index 0000000..3d7c470
--- /dev/null
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/NSObject+YYModel.m
@@ -0,0 +1,1839 @@
+//
+//  NSObject+YYModel.m
+//  YYModel <https://github.com/ibireme/YYModel>
+//
+//  Created by ibireme on 15/5/10.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "NSObject+YYModel.h"
+#import "YYClassInfo.h"
+#import <objc/message.h>
+
+#define force_inline __inline__ __attribute__((always_inline))
+
+/// Foundation Class Type
+typedef NS_ENUM (NSUInteger, YYEncodingNSType) {
+    YYEncodingTypeNSUnknown = 0,
+    YYEncodingTypeNSString,
+    YYEncodingTypeNSMutableString,
+    YYEncodingTypeNSValue,
+    YYEncodingTypeNSNumber,
+    YYEncodingTypeNSDecimalNumber,
+    YYEncodingTypeNSData,
+    YYEncodingTypeNSMutableData,
+    YYEncodingTypeNSDate,
+    YYEncodingTypeNSURL,
+    YYEncodingTypeNSArray,
+    YYEncodingTypeNSMutableArray,
+    YYEncodingTypeNSDictionary,
+    YYEncodingTypeNSMutableDictionary,
+    YYEncodingTypeNSSet,
+    YYEncodingTypeNSMutableSet,
+};
+
+/// Get the Foundation class type from property info.
+static force_inline YYEncodingNSType YYClassGetNSType(Class cls) {
+    if (!cls) return YYEncodingTypeNSUnknown;
+    if ([cls isSubclassOfClass:[NSMutableString class]]) return YYEncodingTypeNSMutableString;
+    if ([cls isSubclassOfClass:[NSString class]]) return YYEncodingTypeNSString;
+    if ([cls isSubclassOfClass:[NSDecimalNumber class]]) return YYEncodingTypeNSDecimalNumber;
+    if ([cls isSubclassOfClass:[NSNumber class]]) return YYEncodingTypeNSNumber;
+    if ([cls isSubclassOfClass:[NSValue class]]) return YYEncodingTypeNSValue;
+    if ([cls isSubclassOfClass:[NSMutableData class]]) return YYEncodingTypeNSMutableData;
+    if ([cls isSubclassOfClass:[NSData class]]) return YYEncodingTypeNSData;
+    if ([cls isSubclassOfClass:[NSDate class]]) return YYEncodingTypeNSDate;
+    if ([cls isSubclassOfClass:[NSURL class]]) return YYEncodingTypeNSURL;
+    if ([cls isSubclassOfClass:[NSMutableArray class]]) return YYEncodingTypeNSMutableArray;
+    if ([cls isSubclassOfClass:[NSArray class]]) return YYEncodingTypeNSArray;
+    if ([cls isSubclassOfClass:[NSMutableDictionary class]]) return YYEncodingTypeNSMutableDictionary;
+    if ([cls isSubclassOfClass:[NSDictionary class]]) return YYEncodingTypeNSDictionary;
+    if ([cls isSubclassOfClass:[NSMutableSet class]]) return YYEncodingTypeNSMutableSet;
+    if ([cls isSubclassOfClass:[NSSet class]]) return YYEncodingTypeNSSet;
+    return YYEncodingTypeNSUnknown;
+}
+
+/// Whether the type is c number.
+static force_inline BOOL YYEncodingTypeIsCNumber(YYEncodingType type) {
+    switch (type & YYEncodingTypeMask) {
+        case YYEncodingTypeBool:
+        case YYEncodingTypeInt8:
+        case YYEncodingTypeUInt8:
+        case YYEncodingTypeInt16:
+        case YYEncodingTypeUInt16:
+        case YYEncodingTypeInt32:
+        case YYEncodingTypeUInt32:
+        case YYEncodingTypeInt64:
+        case YYEncodingTypeUInt64:
+        case YYEncodingTypeFloat:
+        case YYEncodingTypeDouble:
+        case YYEncodingTypeLongDouble: return YES;
+        default: return NO;
+    }
+}
+
+/// Parse a number value from 'id'.
+static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value) {
+    static NSCharacterSet *dot;
+    static NSDictionary *dic;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)];
+        dic = @{@"TRUE" :   @(YES),
+                @"True" :   @(YES),
+                @"true" :   @(YES),
+                @"FALSE" :  @(NO),
+                @"False" :  @(NO),
+                @"false" :  @(NO),
+                @"YES" :    @(YES),
+                @"Yes" :    @(YES),
+                @"yes" :    @(YES),
+                @"NO" :     @(NO),
+                @"No" :     @(NO),
+                @"no" :     @(NO),
+                @"NIL" :    (id)kCFNull,
+                @"Nil" :    (id)kCFNull,
+                @"nil" :    (id)kCFNull,
+                @"NULL" :   (id)kCFNull,
+                @"Null" :   (id)kCFNull,
+                @"null" :   (id)kCFNull,
+                @"(NULL)" : (id)kCFNull,
+                @"(Null)" : (id)kCFNull,
+                @"(null)" : (id)kCFNull,
+                @"<NULL>" : (id)kCFNull,
+                @"<Null>" : (id)kCFNull,
+                @"<null>" : (id)kCFNull};
+    });
+    
+    if (!value || value == (id)kCFNull) return nil;
+    if ([value isKindOfClass:[NSNumber class]]) return value;
+    if ([value isKindOfClass:[NSString class]]) {
+        NSNumber *num = dic[value];
+        if (num != nil) {
+            if (num == (id)kCFNull) return nil;
+            return num;
+        }
+        if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
+            const char *cstring = ((NSString *)value).UTF8String;
+            if (!cstring) return nil;
+            double num = atof(cstring);
+            if (isnan(num) || isinf(num)) return nil;
+            return @(num);
+        } else {
+            const char *cstring = ((NSString *)value).UTF8String;
+            if (!cstring) return nil;
+            return @(atoll(cstring));
+        }
+    }
+    return nil;
+}
+
+/// Parse string to date.
+static force_inline NSDate *YYNSDateFromString(__unsafe_unretained NSString *string) {
+    typedef NSDate* (^YYNSDateParseBlock)(NSString *string);
+    #define kParserNum 34
+    static YYNSDateParseBlock blocks[kParserNum + 1] = {0};
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        {
+            /*
+             2014-01-20  // Google
+             */
+            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+            formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+            formatter.dateFormat = @"yyyy-MM-dd";
+            blocks[10] = ^(NSString *string) { return [formatter dateFromString:string]; };
+        }
+        
+        {
+            /*
+             2014-01-20 12:24:48
+             2014-01-20T12:24:48   // Google
+             2014-01-20 12:24:48.000
+             2014-01-20T12:24:48.000
+             */
+            NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
+            formatter1.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter1.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+            formatter1.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
+            
+            NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
+            formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter2.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+            formatter2.dateFormat = @"yyyy-MM-dd HH:mm:ss";
+
+            NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
+            formatter3.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter3.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+            formatter3.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS";
+
+            NSDateFormatter *formatter4 = [[NSDateFormatter alloc] init];
+            formatter4.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter4.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+            formatter4.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
+            
+            blocks[19] = ^(NSString *string) {
+                if ([string characterAtIndex:10] == 'T') {
+                    return [formatter1 dateFromString:string];
+                } else {
+                    return [formatter2 dateFromString:string];
+                }
+            };
+
+            blocks[23] = ^(NSString *string) {
+                if ([string characterAtIndex:10] == 'T') {
+                    return [formatter3 dateFromString:string];
+                } else {
+                    return [formatter4 dateFromString:string];
+                }
+            };
+        }
+        
+        {
+            /*
+             2014-01-20T12:24:48Z        // Github, Apple
+             2014-01-20T12:24:48+0800    // Facebook
+             2014-01-20T12:24:48+12:00   // Google
+             2014-01-20T12:24:48.000Z
+             2014-01-20T12:24:48.000+0800
+             2014-01-20T12:24:48.000+12:00
+             */
+            NSDateFormatter *formatter = [NSDateFormatter new];
+            formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
+
+            NSDateFormatter *formatter2 = [NSDateFormatter new];
+            formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+            blocks[20] = ^(NSString *string) { return [formatter dateFromString:string]; };
+            blocks[24] = ^(NSString *string) { return [formatter dateFromString:string]?: [formatter2 dateFromString:string]; };
+            blocks[25] = ^(NSString *string) { return [formatter dateFromString:string]; };
+            blocks[28] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
+            blocks[29] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
+        }
+        
+        {
+            /*
+             Fri Sep 04 00:12:21 +0800 2015 // Weibo, Twitter
+             Fri Sep 04 00:12:21.000 +0800 2015
+             */
+            NSDateFormatter *formatter = [NSDateFormatter new];
+            formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
+
+            NSDateFormatter *formatter2 = [NSDateFormatter new];
+            formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+            formatter2.dateFormat = @"EEE MMM dd HH:mm:ss.SSS Z yyyy";
+
+            blocks[30] = ^(NSString *string) { return [formatter dateFromString:string]; };
+            blocks[34] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
+        }
+    });
+    if (!string) return nil;
+    if (string.length > kParserNum) return nil;
+    YYNSDateParseBlock parser = blocks[string.length];
+    if (!parser) return nil;
+    return parser(string);
+    #undef kParserNum
+}
+
+
+/// Get the 'NSBlock' class.
+static force_inline Class YYNSBlockClass() {
+    static Class cls;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        void (^block)(void) = ^{};
+        cls = ((NSObject *)block).class;
+        while (class_getSuperclass(cls) != [NSObject class]) {
+            cls = class_getSuperclass(cls);
+        }
+    });
+    return cls; // current is "NSBlock"
+}
+
+
+
+/**
+ Get the ISO date formatter.
+ 
+ ISO8601 format example:
+ 2010-07-09T16:13:30+12:00
+ 2011-01-11T11:11:11+0000
+ 2011-01-26T19:06:43Z
+ 
+ length: 20/24/25
+ */
+static force_inline NSDateFormatter *YYISODateFormatter() {
+    static NSDateFormatter *formatter = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        formatter = [[NSDateFormatter alloc] init];
+        formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+        formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
+    });
+    return formatter;
+}
+
+/// Get the value with key paths from dictionary
+/// The dic should be NSDictionary, and the keyPath should not be nil.
+static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
+    id value = nil;
+    for (NSUInteger i = 0, max = keyPaths.count; i < max; i++) {
+        value = dic[keyPaths[i]];
+        if (i + 1 < max) {
+            if ([value isKindOfClass:[NSDictionary class]]) {
+                dic = value;
+            } else {
+                return nil;
+            }
+        }
+    }
+    return value;
+}
+
+/// Get the value with multi key (or key path) from dictionary
+/// The dic should be NSDictionary
+static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
+    id value = nil;
+    for (NSString *key in multiKeys) {
+        if ([key isKindOfClass:[NSString class]]) {
+            value = dic[key];
+            if (value) break;
+        } else {
+            value = YYValueForKeyPath(dic, (NSArray *)key);
+            if (value) break;
+        }
+    }
+    return value;
+}
+
+
+
+
+/// A property info in object model.
+@interface _YYModelPropertyMeta : NSObject {
+    @package
+    NSString *_name;             ///< property's name
+    YYEncodingType _type;        ///< property's type
+    YYEncodingNSType _nsType;    ///< property's Foundation type
+    BOOL _isCNumber;             ///< is c number type
+    Class _cls;                  ///< property's class, or nil
+    Class _genericCls;           ///< container's generic class, or nil if threr's no generic class
+    SEL _getter;                 ///< getter, or nil if the instances cannot respond
+    SEL _setter;                 ///< setter, or nil if the instances cannot respond
+    BOOL _isKVCCompatible;       ///< YES if it can access with key-value coding
+    BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver
+    BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary:
+    
+    /*
+     property->key:       _mappedToKey:key     _mappedToKeyPath:nil            _mappedToKeyArray:nil
+     property->keyPath:   _mappedToKey:keyPath _mappedToKeyPath:keyPath(array) _mappedToKeyArray:nil
+     property->keys:      _mappedToKey:keys[0] _mappedToKeyPath:nil/keyPath    _mappedToKeyArray:keys(array)
+     */
+    NSString *_mappedToKey;      ///< the key mapped to
+    NSArray *_mappedToKeyPath;   ///< the key path mapped to (nil if the name is not key path)
+    NSArray *_mappedToKeyArray;  ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys)
+    YYClassPropertyInfo *_info;  ///< property's info
+    _YYModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key.
+}
+@end
+
+@implementation _YYModelPropertyMeta
++ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic {
+    
+    // support pseudo generic class with protocol name
+    if (!generic && propertyInfo.protocols) {
+        for (NSString *protocol in propertyInfo.protocols) {
+            Class cls = objc_getClass(protocol.UTF8String);
+            if (cls) {
+                generic = cls;
+                break;
+            }
+        }
+    }
+    
+    _YYModelPropertyMeta *meta = [self new];
+    meta->_name = propertyInfo.name;
+    meta->_type = propertyInfo.type;
+    meta->_info = propertyInfo;
+    meta->_genericCls = generic;
+    
+    if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeObject) {
+        meta->_nsType = YYClassGetNSType(propertyInfo.cls);
+    } else {
+        meta->_isCNumber = YYEncodingTypeIsCNumber(meta->_type);
+    }
+    if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeStruct) {
+        /*
+         It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
+         */
+        static NSSet *types = nil;
+        static dispatch_once_t onceToken;
+        dispatch_once(&onceToken, ^{
+            NSMutableSet *set = [NSMutableSet new];
+            // 32 bit
+            [set addObject:@"{CGSize=ff}"];
+            [set addObject:@"{CGPoint=ff}"];
+            [set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
+            [set addObject:@"{CGAffineTransform=ffffff}"];
+            [set addObject:@"{UIEdgeInsets=ffff}"];
+            [set addObject:@"{UIOffset=ff}"];
+            // 64 bit
+            [set addObject:@"{CGSize=dd}"];
+            [set addObject:@"{CGPoint=dd}"];
+            [set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
+            [set addObject:@"{CGAffineTransform=dddddd}"];
+            [set addObject:@"{UIEdgeInsets=dddd}"];
+            [set addObject:@"{UIOffset=dd}"];
+            types = set;
+        });
+        if ([types containsObject:propertyInfo.typeEncoding]) {
+            meta->_isStructAvailableForKeyedArchiver = YES;
+        }
+    }
+    meta->_cls = propertyInfo.cls;
+    
+    if (generic) {
+        meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
+    } else if (meta->_cls && meta->_nsType == YYEncodingTypeNSUnknown) {
+        meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
+    }
+    
+    if (propertyInfo.getter) {
+        if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
+            meta->_getter = propertyInfo.getter;
+        }
+    }
+    if (propertyInfo.setter) {
+        if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
+            meta->_setter = propertyInfo.setter;
+        }
+    }
+    
+    if (meta->_getter && meta->_setter) {
+        /*
+         KVC invalid type:
+         long double
+         pointer (such as SEL/CoreFoundation object)
+         */
+        switch (meta->_type & YYEncodingTypeMask) {
+            case YYEncodingTypeBool:
+            case YYEncodingTypeInt8:
+            case YYEncodingTypeUInt8:
+            case YYEncodingTypeInt16:
+            case YYEncodingTypeUInt16:
+            case YYEncodingTypeInt32:
+            case YYEncodingTypeUInt32:
+            case YYEncodingTypeInt64:
+            case YYEncodingTypeUInt64:
+            case YYEncodingTypeFloat:
+            case YYEncodingTypeDouble:
+            case YYEncodingTypeObject:
+            case YYEncodingTypeClass:
+            case YYEncodingTypeBlock:
+            case YYEncodingTypeStruct:
+            case YYEncodingTypeUnion: {
+                meta->_isKVCCompatible = YES;
+            } break;
+            default: break;
+        }
+    }
+    
+    return meta;
+}
+@end
+
+
+/// A class info in object model.
+@interface _YYModelMeta : NSObject {
+    @package
+    YYClassInfo *_classInfo;
+    /// Key:mapped key and key path, Value:_YYModelPropertyMeta.
+    NSDictionary *_mapper;
+    /// Array<_YYModelPropertyMeta>, all property meta of this model.
+    NSArray *_allPropertyMetas;
+    /// Array<_YYModelPropertyMeta>, property meta which is mapped to a key path.
+    NSArray *_keyPathPropertyMetas;
+    /// Array<_YYModelPropertyMeta>, property meta which is mapped to multi keys.
+    NSArray *_multiKeysPropertyMetas;
+    /// The number of mapped key (and key path), same to _mapper.count.
+    NSUInteger _keyMappedCount;
+    /// Model class type.
+    YYEncodingNSType _nsType;
+    
+    BOOL _hasCustomWillTransformFromDictionary;
+    BOOL _hasCustomTransformFromDictionary;
+    BOOL _hasCustomTransformToDictionary;
+    BOOL _hasCustomClassFromDictionary;
+}
+@end
+
+@implementation _YYModelMeta
+- (instancetype)initWithClass:(Class)cls {
+    YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
+    if (!classInfo) return nil;
+    self = [super init];
+    
+    // Get black list
+    NSSet *blacklist = nil;
+    if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
+        NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
+        if (properties) {
+            blacklist = [NSSet setWithArray:properties];
+        }
+    }
+    
+    // Get white list
+    NSSet *whitelist = nil;
+    if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {
+        NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist];
+        if (properties) {
+            whitelist = [NSSet setWithArray:properties];
+        }
+    }
+    
+    // Get container property's generic class
+    NSDictionary *genericMapper = nil;
+    if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
+        genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass];
+        if (genericMapper) {
+            NSMutableDictionary *tmp = [NSMutableDictionary new];
+            [genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
+                if (![key isKindOfClass:[NSString class]]) return;
+                Class meta = object_getClass(obj);
+                if (!meta) return;
+                if (class_isMetaClass(meta)) {
+                    tmp[key] = obj;
+                } else if ([obj isKindOfClass:[NSString class]]) {
+                    Class cls = NSClassFromString(obj);
+                    if (cls) {
+                        tmp[key] = cls;
+                    }
+                }
+            }];
+            genericMapper = tmp;
+        }
+    }
+    
+    // Create all property metas.
+    NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
+    YYClassInfo *curClassInfo = classInfo;
+    while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy)
+        for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
+            if (!propertyInfo.name) continue;
+            if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
+            if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
+            _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
+                                                                    propertyInfo:propertyInfo
+                                                                         generic:genericMapper[propertyInfo.name]];
+            if (!meta || !meta->_name) continue;
+            if (!meta->_getter || !meta->_setter) continue;
+            if (allPropertyMetas[meta->_name]) continue;
+            allPropertyMetas[meta->_name] = meta;
+        }
+        curClassInfo = curClassInfo.superClassInfo;
+    }
+    if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
+    
+    // create mapper
+    NSMutableDictionary *mapper = [NSMutableDictionary new];
+    NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
+    NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new];
+    
+    if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {
+        NSDictionary *customMapper = [(id <YYModel>)cls modelCustomPropertyMapper];
+        [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
+            _YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
+            if (!propertyMeta) return;
+            [allPropertyMetas removeObjectForKey:propertyName];
+            
+            if ([mappedToKey isKindOfClass:[NSString class]]) {
+                if (mappedToKey.length == 0) return;
+                
+                propertyMeta->_mappedToKey = mappedToKey;
+                NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."];
+                for (NSString *onePath in keyPath) {
+                    if (onePath.length == 0) {
+                        NSMutableArray *tmp = keyPath.mutableCopy;
+                        [tmp removeObject:@""];
+                        keyPath = tmp;
+                        break;
+                    }
+                }
+                if (keyPath.count > 1) {
+                    propertyMeta->_mappedToKeyPath = keyPath;
+                    [keyPathPropertyMetas addObject:propertyMeta];
+                }
+                propertyMeta->_next = mapper[mappedToKey] ?: nil;
+                mapper[mappedToKey] = propertyMeta;
+                
+            } else if ([mappedToKey isKindOfClass:[NSArray class]]) {
+                
+                NSMutableArray *mappedToKeyArray = [NSMutableArray new];
+                for (NSString *oneKey in ((NSArray *)mappedToKey)) {
+                    if (![oneKey isKindOfClass:[NSString class]]) continue;
+                    if (oneKey.length == 0) continue;
+                    
+                    NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
+                    if (keyPath.count > 1) {
+                        [mappedToKeyArray addObject:keyPath];
+                    } else {
+                        [mappedToKeyArray addObject:oneKey];
+                    }
+                    
+                    if (!propertyMeta->_mappedToKey) {
+                        propertyMeta->_mappedToKey = oneKey;
+                        propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
+                    }
+                }
+                if (!propertyMeta->_mappedToKey) return;
+                
+                propertyMeta->_mappedToKeyArray = mappedToKeyArray;
+                [multiKeysPropertyMetas addObject:propertyMeta];
+                
+                propertyMeta->_next = mapper[mappedToKey] ?: nil;
+                mapper[mappedToKey] = propertyMeta;
+            }
+        }];
+    }
+    
+    [allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
+        propertyMeta->_mappedToKey = name;
+        propertyMeta->_next = mapper[name] ?: nil;
+        mapper[name] = propertyMeta;
+    }];
+    
+    if (mapper.count) _mapper = mapper;
+    if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
+    if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
+    
+    _classInfo = classInfo;
+    _keyMappedCount = _allPropertyMetas.count;
+    _nsType = YYClassGetNSType(cls);
+    _hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
+    _hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
+    _hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
+    _hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
+    
+    return self;
+}
+
+/// Returns the cached model class meta
++ (instancetype)metaWithClass:(Class)cls {
+    if (!cls) return nil;
+    static CFMutableDictionaryRef cache;
+    static dispatch_once_t onceToken;
+    static dispatch_semaphore_t lock;
+    dispatch_once(&onceToken, ^{
+        cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+        lock = dispatch_semaphore_create(1);
+    });
+    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+    _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
+    dispatch_semaphore_signal(lock);
+    if (!meta || meta->_classInfo.needUpdate) {
+        meta = [[_YYModelMeta alloc] initWithClass:cls];
+        if (meta) {
+            dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+            CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
+            dispatch_semaphore_signal(lock);
+        }
+    }
+    return meta;
+}
+
+@end
+
+
+/**
+ Get number from property.
+ @discussion Caller should hold strong reference to the parameters before this function returns.
+ @param model Should not be nil.
+ @param meta  Should not be nil, meta.isCNumber should be YES, meta.getter should not be nil.
+ @return A number object, or nil if failed.
+ */
+static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model,
+                                                            __unsafe_unretained _YYModelPropertyMeta *meta) {
+    switch (meta->_type & YYEncodingTypeMask) {
+        case YYEncodingTypeBool: {
+            return @(((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeInt8: {
+            return @(((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeUInt8: {
+            return @(((uint8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeInt16: {
+            return @(((int16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeUInt16: {
+            return @(((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeInt32: {
+            return @(((int32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeUInt32: {
+            return @(((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeInt64: {
+            return @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeUInt64: {
+            return @(((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
+        }
+        case YYEncodingTypeFloat: {
+            float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
+            if (isnan(num) || isinf(num)) return nil;
+            return @(num);
+        }
+        case YYEncodingTypeDouble: {
+            double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
+            if (isnan(num) || isinf(num)) return nil;
+            return @(num);
+        }
+        case YYEncodingTypeLongDouble: {
+            double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
+            if (isnan(num) || isinf(num)) return nil;
+            return @(num);
+        }
+        default: return nil;
+    }
+}
+
+/**
+ Set number to property.
+ @discussion Caller should hold strong reference to the parameters before this function returns.
+ @param model Should not be nil.
+ @param num   Can be nil.
+ @param meta  Should not be nil, meta.isCNumber should be YES, meta.setter should not be nil.
+ */
+static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
+                                                  __unsafe_unretained NSNumber *num,
+                                                  __unsafe_unretained _YYModelPropertyMeta *meta) {
+    switch (meta->_type & YYEncodingTypeMask) {
+        case YYEncodingTypeBool: {
+            ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
+        } break;
+        case YYEncodingTypeInt8: {
+            ((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
+        } break;
+        case YYEncodingTypeUInt8: {
+            ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue);
+        } break;
+        case YYEncodingTypeInt16: {
+            ((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue);
+        } break;
+        case YYEncodingTypeUInt16: {
+            ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue);
+        } break;
+        case YYEncodingTypeInt32: {
+            ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue);
+        }
+        case YYEncodingTypeUInt32: {
+            ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue);
+        } break;
+        case YYEncodingTypeInt64: {
+            if ([num isKindOfClass:[NSDecimalNumber class]]) {
+                ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
+            } else {
+                ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue);
+            }
+        } break;
+        case YYEncodingTypeUInt64: {
+            if ([num isKindOfClass:[NSDecimalNumber class]]) {
+                ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
+            } else {
+                ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue);
+            }
+        } break;
+        case YYEncodingTypeFloat: {
+            float f = num.floatValue;
+            if (isnan(f) || isinf(f)) f = 0;
+            ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f);
+        } break;
+        case YYEncodingTypeDouble: {
+            double d = num.doubleValue;
+            if (isnan(d) || isinf(d)) d = 0;
+            ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d);
+        } break;
+        case YYEncodingTypeLongDouble: {
+            long double d = num.doubleValue;
+            if (isnan(d) || isinf(d)) d = 0;
+            ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d);
+        } // break; commented for code coverage in next line
+        default: break;
+    }
+}
+
+/**
+ Set value to model with a property meta.
+ 
+ @discussion Caller should hold strong reference to the parameters before this function returns.
+ 
+ @param model Should not be nil.
+ @param value Should not be nil, but can be NSNull.
+ @param meta  Should not be nil, and meta->_setter should not be nil.
+ */
+static void ModelSetValueForProperty(__unsafe_unretained id model,
+                                     __unsafe_unretained id value,
+                                     __unsafe_unretained _YYModelPropertyMeta *meta) {
+    if (meta->_isCNumber) {
+        NSNumber *num = YYNSNumberCreateFromID(value);
+        ModelSetNumberToProperty(model, num, meta);
+        if (num != nil) [num class]; // hold the number
+    } else if (meta->_nsType) {
+        if (value == (id)kCFNull) {
+            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
+        } else {
+            switch (meta->_nsType) {
+                case YYEncodingTypeNSString:
+                case YYEncodingTypeNSMutableString: {
+                    if ([value isKindOfClass:[NSString class]]) {
+                        if (meta->_nsType == YYEncodingTypeNSString) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                        } else {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy);
+                        }
+                    } else if ([value isKindOfClass:[NSNumber class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                       meta->_setter,
+                                                                       (meta->_nsType == YYEncodingTypeNSString) ?
+                                                                       ((NSNumber *)value).stringValue :
+                                                                       ((NSNumber *)value).stringValue.mutableCopy);
+                    } else if ([value isKindOfClass:[NSData class]]) {
+                        NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
+                    } else if ([value isKindOfClass:[NSURL class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                       meta->_setter,
+                                                                       (meta->_nsType == YYEncodingTypeNSString) ?
+                                                                       ((NSURL *)value).absoluteString :
+                                                                       ((NSURL *)value).absoluteString.mutableCopy);
+                    } else if ([value isKindOfClass:[NSAttributedString class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                       meta->_setter,
+                                                                       (meta->_nsType == YYEncodingTypeNSString) ?
+                                                                       ((NSAttributedString *)value).string :
+                                                                       ((NSAttributedString *)value).string.mutableCopy);
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSValue:
+                case YYEncodingTypeNSNumber:
+                case YYEncodingTypeNSDecimalNumber: {
+                    if (meta->_nsType == YYEncodingTypeNSNumber) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
+                    } else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) {
+                        if ([value isKindOfClass:[NSDecimalNumber class]]) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                        } else if ([value isKindOfClass:[NSNumber class]]) {
+                            NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
+                        } else if ([value isKindOfClass:[NSString class]]) {
+                            NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:value];
+                            NSDecimal dec = decNum.decimalValue;
+                            if (dec._length == 0 && dec._isNegative) {
+                                decNum = nil; // NaN
+                            }
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
+                        }
+                    } else { // YYEncodingTypeNSValue
+                        if ([value isKindOfClass:[NSValue class]]) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                        }
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSData:
+                case YYEncodingTypeNSMutableData: {
+                    if ([value isKindOfClass:[NSData class]]) {
+                        if (meta->_nsType == YYEncodingTypeNSData) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                        } else {
+                            NSMutableData *data = ((NSData *)value).mutableCopy;
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
+                        }
+                    } else if ([value isKindOfClass:[NSString class]]) {
+                        NSData *data = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
+                        if (meta->_nsType == YYEncodingTypeNSMutableData) {
+                            data = ((NSData *)data).mutableCopy;
+                        }
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSDate: {
+                    if ([value isKindOfClass:[NSDate class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                    } else if ([value isKindOfClass:[NSString class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSURL: {
+                    if ([value isKindOfClass:[NSURL class]]) {
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                    } else if ([value isKindOfClass:[NSString class]]) {
+                        NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+                        NSString *str = [value stringByTrimmingCharactersInSet:set];
+                        if (str.length == 0) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, nil);
+                        } else {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, [[NSURL alloc] initWithString:str]);
+                        }
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSArray:
+                case YYEncodingTypeNSMutableArray: {
+                    if (meta->_genericCls) {
+                        NSArray *valueArr = nil;
+                        if ([value isKindOfClass:[NSArray class]]) valueArr = value;
+                        else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects;
+                        if (valueArr) {
+                            NSMutableArray *objectArr = [NSMutableArray new];
+                            for (id one in valueArr) {
+                                if ([one isKindOfClass:meta->_genericCls]) {
+                                    [objectArr addObject:one];
+                                } else if ([one isKindOfClass:[NSDictionary class]]) {
+                                    Class cls = meta->_genericCls;
+                                    if (meta->_hasCustomClassFromDictionary) {
+                                        cls = [cls modelCustomClassForDictionary:one];
+                                        if (!cls) cls = meta->_genericCls; // for xcode code coverage
+                                    }
+                                    NSObject *newOne = [cls new];
+                                    [newOne yy_modelSetWithDictionary:one];
+                                    if (newOne) [objectArr addObject:newOne];
+                                }
+                            }
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
+                        }
+                    } else {
+                        if ([value isKindOfClass:[NSArray class]]) {
+                            if (meta->_nsType == YYEncodingTypeNSArray) {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                            } else {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                               meta->_setter,
+                                                                               ((NSArray *)value).mutableCopy);
+                            }
+                        } else if ([value isKindOfClass:[NSSet class]]) {
+                            if (meta->_nsType == YYEncodingTypeNSArray) {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSSet *)value).allObjects);
+                            } else {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                               meta->_setter,
+                                                                               ((NSSet *)value).allObjects.mutableCopy);
+                            }
+                        }
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSDictionary:
+                case YYEncodingTypeNSMutableDictionary: {
+                    if ([value isKindOfClass:[NSDictionary class]]) {
+                        if (meta->_genericCls) {
+                            NSMutableDictionary *dic = [NSMutableDictionary new];
+                            [((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(NSString *oneKey, id oneValue, BOOL *stop) {
+                                if ([oneValue isKindOfClass:[NSDictionary class]]) {
+                                    Class cls = meta->_genericCls;
+                                    if (meta->_hasCustomClassFromDictionary) {
+                                        cls = [cls modelCustomClassForDictionary:oneValue];
+                                        if (!cls) cls = meta->_genericCls; // for xcode code coverage
+                                    }
+                                    NSObject *newOne = [cls new];
+                                    [newOne yy_modelSetWithDictionary:(id)oneValue];
+                                    if (newOne) dic[oneKey] = newOne;
+                                }
+                            }];
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
+                        } else {
+                            if (meta->_nsType == YYEncodingTypeNSDictionary) {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
+                            } else {
+                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                               meta->_setter,
+                                                                               ((NSDictionary *)value).mutableCopy);
+                            }
+                        }
+                    }
+                } break;
+                    
+                case YYEncodingTypeNSSet:
+                case YYEncodingTypeNSMutableSet: {
+                    NSSet *valueSet = nil;
+                    if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
+                    else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
+                    
+                    if (meta->_genericCls) {
+                        NSMutableSet *set = [NSMutableSet new];
+                        for (id one in valueSet) {
+                            if ([one isKindOfClass:meta->_genericCls]) {
+                                [set addObject:one];
+                            } else if ([one isKindOfClass:[NSDictionary class]]) {
+                                Class cls = meta->_genericCls;
+                                if (meta->_hasCustomClassFromDictionary) {
+                                    cls = [cls modelCustomClassForDictionary:one];
+                                    if (!cls) cls = meta->_genericCls; // for xcode code coverage
+                                }
+                                NSObject *newOne = [cls new];
+                                [newOne yy_modelSetWithDictionary:one];
+                                if (newOne) [set addObject:newOne];
+                            }
+                        }
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, set);
+                    } else {
+                        if (meta->_nsType == YYEncodingTypeNSSet) {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, valueSet);
+                        } else {
+                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
+                                                                           meta->_setter,
+                                                                           ((NSSet *)valueSet).mutableCopy);
+                        }
+                    }
+                } // break; commented for code coverage in next line
+                    
+                default: break;
+            }
+        }
+    } else {
+        BOOL isNull = (value == (id)kCFNull);
+        switch (meta->_type & YYEncodingTypeMask) {
+            case YYEncodingTypeObject: {
+                Class cls = meta->_genericCls ?: meta->_cls;
+                if (isNull) {
+                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
+                } else if ([value isKindOfClass:cls] || !cls) {
+                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
+                } else if ([value isKindOfClass:[NSDictionary class]]) {
+                    NSObject *one = nil;
+                    if (meta->_getter) {
+                        one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
+                    }
+                    if (one) {
+                        [one yy_modelSetWithDictionary:value];
+                    } else {
+                        if (meta->_hasCustomClassFromDictionary) {
+                            cls = [cls modelCustomClassForDictionary:value] ?: cls;
+                        }
+                        one = [cls new];
+                        [one yy_modelSetWithDictionary:value];
+                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
+                    }
+                }
+            } break;
+                
+            case YYEncodingTypeClass: {
+                if (isNull) {
+                    ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
+                } else {
+                    Class cls = nil;
+                    if ([value isKindOfClass:[NSString class]]) {
+                        cls = NSClassFromString(value);
+                        if (cls) {
+                            ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
+                        }
+                    } else {
+                        cls = object_getClass(value);
+                        if (cls) {
+                            if (class_isMetaClass(cls)) {
+                                ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
+                            }
+                        }
+                    }
+                }
+            } break;
+                
+            case  YYEncodingTypeSEL: {
+                if (isNull) {
+                    ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
+                } else if ([value isKindOfClass:[NSString class]]) {
+                    SEL sel = NSSelectorFromString(value);
+                    if (sel) ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)sel);
+                }
+            } break;
+                
+            case YYEncodingTypeBlock: {
+                if (isNull) {
+                    ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
+                } else if ([value isKindOfClass:YYNSBlockClass()]) {
+                    ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
+                }
+            } break;
+                
+            case YYEncodingTypeStruct:
+            case YYEncodingTypeUnion:
+            case YYEncodingTypeCArray: {
+                if ([value isKindOfClass:[NSValue class]]) {
+                    const char *valueType = ((NSValue *)value).objCType;
+                    const char *metaType = meta->_info.typeEncoding.UTF8String;
+                    if (valueType && metaType && strcmp(valueType, metaType) == 0) {
+                        [model setValue:value forKey:meta->_name];
+                    }
+                }
+            } break;
+                
+            case YYEncodingTypePointer:
+            case YYEncodingTypeCString: {
+                if (isNull) {
+                    ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
+                } else if ([value isKindOfClass:[NSValue class]]) {
+                    NSValue *nsValue = value;
+                    if (nsValue.objCType && strcmp(nsValue.objCType, "^v") == 0) {
+                        ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, nsValue.pointerValue);
+                    }
+                }
+            } // break; commented for code coverage in next line
+                
+            default: break;
+        }
+    }
+}
+
+
+typedef struct {
+    void *modelMeta;  ///< _YYModelMeta
+    void *model;      ///< id (self)
+    void *dictionary; ///< NSDictionary (json)
+} ModelSetContext;
+
+/**
+ Apply function for dictionary, to set the key-value pair to model.
+ 
+ @param _key     should not be nil, NSString.
+ @param _value   should not be nil.
+ @param _context _context.modelMeta and _context.model should not be nil.
+ */
+static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
+    ModelSetContext *context = _context;
+    __unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
+    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
+    __unsafe_unretained id model = (__bridge id)(context->model);
+    while (propertyMeta) {
+        if (propertyMeta->_setter) {
+            ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
+        }
+        propertyMeta = propertyMeta->_next;
+    };
+}
+
+/**
+ Apply function for model property meta, to set dictionary to model.
+ 
+ @param _propertyMeta should not be nil, _YYModelPropertyMeta.
+ @param _context      _context.model and _context.dictionary should not be nil.
+ */
+static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
+    ModelSetContext *context = _context;
+    __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
+    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
+    if (!propertyMeta->_setter) return;
+    id value = nil;
+    
+    if (propertyMeta->_mappedToKeyArray) {
+        value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
+    } else if (propertyMeta->_mappedToKeyPath) {
+        value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
+    } else {
+        value = [dictionary objectForKey:propertyMeta->_mappedToKey];
+    }
+    
+    if (value) {
+        __unsafe_unretained id model = (__bridge id)(context->model);
+        ModelSetValueForProperty(model, value, propertyMeta);
+    }
+}
+
+/**
+ Returns a valid JSON object (NSArray/NSDictionary/NSString/NSNumber/NSNull), 
+ or nil if an error occurs.
+ 
+ @param model Model, can be nil.
+ @return JSON object, nil if an error occurs.
+ */
+static id ModelToJSONObjectRecursive(NSObject *model) {
+    if (!model || model == (id)kCFNull) return model;
+    if ([model isKindOfClass:[NSString class]]) return model;
+    if ([model isKindOfClass:[NSNumber class]]) return model;
+    if ([model isKindOfClass:[NSDictionary class]]) {
+        if ([NSJSONSerialization isValidJSONObject:model]) return model;
+        NSMutableDictionary *newDic = [NSMutableDictionary new];
+        [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
+            NSString *stringKey = [key isKindOfClass:[NSString class]] ? key : key.description;
+            if (!stringKey) return;
+            id jsonObj = ModelToJSONObjectRecursive(obj);
+            if (!jsonObj) jsonObj = (id)kCFNull;
+            newDic[stringKey] = jsonObj;
+        }];
+        return newDic;
+    }
+    if ([model isKindOfClass:[NSSet class]]) {
+        NSArray *array = ((NSSet *)model).allObjects;
+        if ([NSJSONSerialization isValidJSONObject:array]) return array;
+        NSMutableArray *newArray = [NSMutableArray new];
+        for (id obj in array) {
+            if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
+                [newArray addObject:obj];
+            } else {
+                id jsonObj = ModelToJSONObjectRecursive(obj);
+                if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
+            }
+        }
+        return newArray;
+    }
+    if ([model isKindOfClass:[NSArray class]]) {
+        if ([NSJSONSerialization isValidJSONObject:model]) return model;
+        NSMutableArray *newArray = [NSMutableArray new];
+        for (id obj in (NSArray *)model) {
+            if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
+                [newArray addObject:obj];
+            } else {
+                id jsonObj = ModelToJSONObjectRecursive(obj);
+                if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
+            }
+        }
+        return newArray;
+    }
+    if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
+    if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
+    if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
+    if ([model isKindOfClass:[NSData class]]) return nil;
+    
+    
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
+    if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
+    NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
+    __unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block
+    [modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
+        if (!propertyMeta->_getter) return;
+        
+        id value = nil;
+        if (propertyMeta->_isCNumber) {
+            value = ModelCreateNumberFromProperty(model, propertyMeta);
+        } else if (propertyMeta->_nsType) {
+            id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
+            value = ModelToJSONObjectRecursive(v);
+        } else {
+            switch (propertyMeta->_type & YYEncodingTypeMask) {
+                case YYEncodingTypeObject: {
+                    id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
+                    value = ModelToJSONObjectRecursive(v);
+                    if (value == (id)kCFNull) value = nil;
+                } break;
+                case YYEncodingTypeClass: {
+                    Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
+                    value = v ? NSStringFromClass(v) : nil;
+                } break;
+                case YYEncodingTypeSEL: {
+                    SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
+                    value = v ? NSStringFromSelector(v) : nil;
+                } break;
+                default: break;
+            }
+        }
+        if (!value) return;
+        
+        if (propertyMeta->_mappedToKeyPath) {
+            NSMutableDictionary *superDic = dic;
+            NSMutableDictionary *subDic = nil;
+            for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
+                NSString *key = propertyMeta->_mappedToKeyPath[i];
+                if (i + 1 == max) { // end
+                    if (!superDic[key]) superDic[key] = value;
+                    break;
+                }
+                
+                subDic = superDic[key];
+                if (subDic) {
+                    if ([subDic isKindOfClass:[NSDictionary class]]) {
+                        subDic = subDic.mutableCopy;
+                        superDic[key] = subDic;
+                    } else {
+                        break;
+                    }
+                } else {
+                    subDic = [NSMutableDictionary new];
+                    superDic[key] = subDic;
+                }
+                superDic = subDic;
+                subDic = nil;
+            }
+        } else {
+            if (!dic[propertyMeta->_mappedToKey]) {
+                dic[propertyMeta->_mappedToKey] = value;
+            }
+        }
+    }];
+    
+    if (modelMeta->_hasCustomTransformToDictionary) {
+        BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic];
+        if (!suc) return nil;
+    }
+    return result;
+}
+
+/// Add indent to string (exclude first line)
+static NSMutableString *ModelDescriptionAddIndent(NSMutableString *desc, NSUInteger indent) {
+    for (NSUInteger i = 0, max = desc.length; i < max; i++) {
+        unichar c = [desc characterAtIndex:i];
+        if (c == '\n') {
+            for (NSUInteger j = 0; j < indent; j++) {
+                [desc insertString:@"    " atIndex:i + 1];
+            }
+            i += indent * 4;
+            max += indent * 4;
+        }
+    }
+    return desc;
+}
+
+/// Generate a description string
+static NSString *ModelDescription(NSObject *model) {
+    static const int kDescMaxLength = 100;
+    if (!model) return @"<nil>";
+    if (model == (id)kCFNull) return @"<null>";
+    if (![model isKindOfClass:[NSObject class]]) return [NSString stringWithFormat:@"%@",model];
+    
+    
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:model.class];
+    switch (modelMeta->_nsType) {
+        case YYEncodingTypeNSString: case YYEncodingTypeNSMutableString: {
+            return [NSString stringWithFormat:@"\"%@\"",model];
+        }
+        
+        case YYEncodingTypeNSValue:
+        case YYEncodingTypeNSData: case YYEncodingTypeNSMutableData: {
+            NSString *tmp = model.description;
+            if (tmp.length > kDescMaxLength) {
+                tmp = [tmp substringToIndex:kDescMaxLength];
+                tmp = [tmp stringByAppendingString:@"..."];
+            }
+            return tmp;
+        }
+            
+        case YYEncodingTypeNSNumber:
+        case YYEncodingTypeNSDecimalNumber:
+        case YYEncodingTypeNSDate:
+        case YYEncodingTypeNSURL: {
+            return [NSString stringWithFormat:@"%@",model];
+        }
+            
+        case YYEncodingTypeNSSet: case YYEncodingTypeNSMutableSet: {
+            model = ((NSSet *)model).allObjects;
+        } // no break
+            
+        case YYEncodingTypeNSArray: case YYEncodingTypeNSMutableArray: {
+            NSArray *array = (id)model;
+            NSMutableString *desc = [NSMutableString new];
+            if (array.count == 0) {
+                return [desc stringByAppendingString:@"[]"];
+            } else {
+                [desc appendFormat:@"[\n"];
+                for (NSUInteger i = 0, max = array.count; i < max; i++) {
+                    NSObject *obj = array[i];
+                    [desc appendString:@"    "];
+                    [desc appendString:ModelDescriptionAddIndent(ModelDescription(obj).mutableCopy, 1)];
+                    [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
+                }
+                [desc appendString:@"]"];
+                return desc;
+            }
+        }
+        case YYEncodingTypeNSDictionary: case YYEncodingTypeNSMutableDictionary: {
+            NSDictionary *dic = (id)model;
+            NSMutableString *desc = [NSMutableString new];
+            if (dic.count == 0) {
+                return [desc stringByAppendingString:@"{}"];
+            } else {
+                NSArray *keys = dic.allKeys;
+                
+                [desc appendFormat:@"{\n"];
+                for (NSUInteger i = 0, max = keys.count; i < max; i++) {
+                    NSString *key = keys[i];
+                    NSObject *value = dic[key];
+                    [desc appendString:@"    "];
+                    [desc appendFormat:@"%@ = %@",key, ModelDescriptionAddIndent(ModelDescription(value).mutableCopy, 1)];
+                    [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
+                }
+                [desc appendString:@"}"];
+            }
+            return desc;
+        }
+        
+        default: {
+            NSMutableString *desc = [NSMutableString new];
+            [desc appendFormat:@"<%@: %p>", model.class, model];
+            if (modelMeta->_allPropertyMetas.count == 0) return desc;
+            
+            // sort property names
+            NSArray *properties = [modelMeta->_allPropertyMetas
+                                   sortedArrayUsingComparator:^NSComparisonResult(_YYModelPropertyMeta *p1, _YYModelPropertyMeta *p2) {
+                                       return [p1->_name compare:p2->_name];
+                                   }];
+            
+            [desc appendFormat:@" {\n"];
+            for (NSUInteger i = 0, max = properties.count; i < max; i++) {
+                _YYModelPropertyMeta *property = properties[i];
+                NSString *propertyDesc;
+                if (property->_isCNumber) {
+                    NSNumber *num = ModelCreateNumberFromProperty(model, property);
+                    propertyDesc = num.stringValue;
+                } else {
+                    switch (property->_type & YYEncodingTypeMask) {
+                        case YYEncodingTypeObject: {
+                            id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
+                            propertyDesc = ModelDescription(v);
+                            if (!propertyDesc) propertyDesc = @"<nil>";
+                        } break;
+                        case YYEncodingTypeClass: {
+                            id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
+                            propertyDesc = ((NSObject *)v).description;
+                            if (!propertyDesc) propertyDesc = @"<nil>";
+                        } break;
+                        case YYEncodingTypeSEL: {
+                            SEL sel = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
+                            if (sel) propertyDesc = NSStringFromSelector(sel);
+                            else propertyDesc = @"<NULL>";
+                        } break;
+                        case YYEncodingTypeBlock: {
+                            id block = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
+                            propertyDesc = block ? ((NSObject *)block).description : @"<nil>";
+                        } break;
+                        case YYEncodingTypeCArray: case YYEncodingTypeCString: case YYEncodingTypePointer: {
+                            void *pointer = ((void* (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
+                            propertyDesc = [NSString stringWithFormat:@"%p",pointer];
+                        } break;
+                        case YYEncodingTypeStruct: case YYEncodingTypeUnion: {
+                            NSValue *value = [model valueForKey:property->_name];
+                            propertyDesc = value ? value.description : @"{unknown}";
+                        } break;
+                        default: propertyDesc = @"<unknown>";
+                    }
+                }
+                
+                propertyDesc = ModelDescriptionAddIndent(propertyDesc.mutableCopy, 1);
+                [desc appendFormat:@"    %@ = %@",property->_name, propertyDesc];
+                [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
+            }
+            [desc appendFormat:@"}"];
+            return desc;
+        }
+    }
+}
+
+
+@implementation NSObject (YYModel)
+
++ (NSDictionary *)_yy_dictionaryWithJSON:(id)json {
+    if (!json || json == (id)kCFNull) return nil;
+    NSDictionary *dic = nil;
+    NSData *jsonData = nil;
+    if ([json isKindOfClass:[NSDictionary class]]) {
+        dic = json;
+    } else if ([json isKindOfClass:[NSString class]]) {
+        jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
+    } else if ([json isKindOfClass:[NSData class]]) {
+        jsonData = json;
+    }
+    if (jsonData) {
+        dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
+        if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
+    }
+    return dic;
+}
+
++ (instancetype)yy_modelWithJSON:(id)json {
+    NSDictionary *dic = [self _yy_dictionaryWithJSON:json];
+    return [self yy_modelWithDictionary:dic];
+}
+
++ (instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary {
+    if (!dictionary || dictionary == (id)kCFNull) return nil;
+    if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
+    
+    Class cls = [self class];
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
+    if (modelMeta->_hasCustomClassFromDictionary) {
+        cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
+    }
+    
+    NSObject *one = [cls new];
+    if ([one yy_modelSetWithDictionary:dictionary]) return one;
+    return nil;
+}
+
+- (BOOL)yy_modelSetWithJSON:(id)json {
+    NSDictionary *dic = [NSObject _yy_dictionaryWithJSON:json];
+    return [self yy_modelSetWithDictionary:dic];
+}
+
+- (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic {
+    if (!dic || dic == (id)kCFNull) return NO;
+    if (![dic isKindOfClass:[NSDictionary class]]) return NO;
+    
+
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
+    if (modelMeta->_keyMappedCount == 0) return NO;
+    
+    if (modelMeta->_hasCustomWillTransformFromDictionary) {
+        dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
+        if (![dic isKindOfClass:[NSDictionary class]]) return NO;
+    }
+    
+    ModelSetContext context = {0};
+    context.modelMeta = (__bridge void *)(modelMeta);
+    context.model = (__bridge void *)(self);
+    context.dictionary = (__bridge void *)(dic);
+    
+    
+    if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
+        CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
+        if (modelMeta->_keyPathPropertyMetas) {
+            CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
+                                 CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
+                                 ModelSetWithPropertyMetaArrayFunction,
+                                 &context);
+        }
+        if (modelMeta->_multiKeysPropertyMetas) {
+            CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
+                                 CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
+                                 ModelSetWithPropertyMetaArrayFunction,
+                                 &context);
+        }
+    } else {
+        CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
+                             CFRangeMake(0, modelMeta->_keyMappedCount),
+                             ModelSetWithPropertyMetaArrayFunction,
+                             &context);
+    }
+    
+    if (modelMeta->_hasCustomTransformFromDictionary) {
+        return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
+    }
+    return YES;
+}
+
+- (id)yy_modelToJSONObject {
+    /*
+     Apple said:
+     The top level object is an NSArray or NSDictionary.
+     All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
+     All dictionary keys are instances of NSString.
+     Numbers are not NaN or infinity.
+     */
+    id jsonObject = ModelToJSONObjectRecursive(self);
+    if ([jsonObject isKindOfClass:[NSArray class]]) return jsonObject;
+    if ([jsonObject isKindOfClass:[NSDictionary class]]) return jsonObject;
+    return nil;
+}
+
+- (NSData *)yy_modelToJSONData {
+    id jsonObject = [self yy_modelToJSONObject];
+    if (!jsonObject) return nil;
+    return [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:NULL];
+}
+
+- (NSString *)yy_modelToJSONString {
+    NSData *jsonData = [self yy_modelToJSONData];
+    if (jsonData.length == 0) return nil;
+    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+}
+
+- (id)yy_modelCopy{
+    if (self == (id)kCFNull) return self;
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
+    if (modelMeta->_nsType) return [self copy];
+    
+    NSObject *one = [self.class new];
+    for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
+        if (!propertyMeta->_getter || !propertyMeta->_setter) continue;
+        
+        if (propertyMeta->_isCNumber) {
+            switch (propertyMeta->_type & YYEncodingTypeMask) {
+                case YYEncodingTypeBool: {
+                    bool num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeInt8:
+                case YYEncodingTypeUInt8: {
+                    uint8_t num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeInt16:
+                case YYEncodingTypeUInt16: {
+                    uint16_t num = ((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeInt32:
+                case YYEncodingTypeUInt32: {
+                    uint32_t num = ((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeInt64:
+                case YYEncodingTypeUInt64: {
+                    uint64_t num = ((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeFloat: {
+                    float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeDouble: {
+                    double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } break;
+                case YYEncodingTypeLongDouble: {
+                    long double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
+                } // break; commented for code coverage in next line
+                default: break;
+            }
+        } else {
+            switch (propertyMeta->_type & YYEncodingTypeMask) {
+                case YYEncodingTypeObject:
+                case YYEncodingTypeClass:
+                case YYEncodingTypeBlock: {
+                    id value = ((id (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
+                } break;
+                case YYEncodingTypeSEL:
+                case YYEncodingTypePointer:
+                case YYEncodingTypeCString: {
+                    size_t value = ((size_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
+                    ((void (*)(id, SEL, size_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
+                } break;
+                case YYEncodingTypeStruct:
+                case YYEncodingTypeUnion: {
+                    @try {
+                        NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
+                        if (value) {
+                            [one setValue:value forKey:propertyMeta->_name];
+                        }
+                    } @catch (NSException *exception) {}
+                } // break; commented for code coverage in next line
+                default: break;
+            }
+        }
+    }
+    return one;
+}
+
+- (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder {
+    if (!aCoder) return;
+    if (self == (id)kCFNull) {
+        [((id<NSCoding>)self)encodeWithCoder:aCoder];
+        return;
+    }
+    
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
+    if (modelMeta->_nsType) {
+        [((id<NSCoding>)self)encodeWithCoder:aCoder];
+        return;
+    }
+    
+    for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
+        if (!propertyMeta->_getter) return;
+        
+        if (propertyMeta->_isCNumber) {
+            NSNumber *value = ModelCreateNumberFromProperty(self, propertyMeta);
+            if (value != nil) [aCoder encodeObject:value forKey:propertyMeta->_name];
+        } else {
+            switch (propertyMeta->_type & YYEncodingTypeMask) {
+                case YYEncodingTypeObject: {
+                    id value = ((id (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
+                    if (value && (propertyMeta->_nsType || [value respondsToSelector:@selector(encodeWithCoder:)])) {
+                        if ([value isKindOfClass:[NSValue class]]) {
+                            if ([value isKindOfClass:[NSNumber class]]) {
+                                [aCoder encodeObject:value forKey:propertyMeta->_name];
+                            }
+                        } else {
+                            [aCoder encodeObject:value forKey:propertyMeta->_name];
+                        }
+                    }
+                } break;
+                case YYEncodingTypeSEL: {
+                    SEL value = ((SEL (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
+                    if (value) {
+                        NSString *str = NSStringFromSelector(value);
+                        [aCoder encodeObject:str forKey:propertyMeta->_name];
+                    }
+                } break;
+                case YYEncodingTypeStruct:
+                case YYEncodingTypeUnion: {
+                    if (propertyMeta->_isKVCCompatible && propertyMeta->_isStructAvailableForKeyedArchiver) {
+                        @try {
+                            NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
+                            [aCoder encodeObject:value forKey:propertyMeta->_name];
+                        } @catch (NSException *exception) {}
+                    }
+                } break;
+                    
+                default:
+                    break;
+            }
+        }
+    }
+}
+
+- (id)yy_modelInitWithCoder:(NSCoder *)aDecoder {
+    if (!aDecoder) return self;
+    if (self == (id)kCFNull) return self;    
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
+    if (modelMeta->_nsType) return self;
+    
+    for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
+        if (!propertyMeta->_setter) continue;
+        
+        if (propertyMeta->_isCNumber) {
+            NSNumber *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
+            if ([value isKindOfClass:[NSNumber class]]) {
+                ModelSetNumberToProperty(self, value, propertyMeta);
+                [value class];
+            }
+        } else {
+            YYEncodingType type = propertyMeta->_type & YYEncodingTypeMask;
+            switch (type) {
+                case YYEncodingTypeObject: {
+                    id value = [aDecoder decodeObjectForKey:propertyMeta->_name];
+                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, propertyMeta->_setter, value);
+                } break;
+                case YYEncodingTypeSEL: {
+                    NSString *str = [aDecoder decodeObjectForKey:propertyMeta->_name];
+                    if ([str isKindOfClass:[NSString class]]) {
+                        SEL sel = NSSelectorFromString(str);
+                        ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_setter, sel);
+                    }
+                } break;
+                case YYEncodingTypeStruct:
+                case YYEncodingTypeUnion: {
+                    if (propertyMeta->_isKVCCompatible) {
+                        @try {
+                            NSValue *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
+                            if (value) [self setValue:value forKey:propertyMeta->_name];
+                        } @catch (NSException *exception) {}
+                    }
+                } break;
+                    
+                default:
+                    break;
+            }
+        }
+    }
+    return self;
+}
+
+- (NSUInteger)yy_modelHash {
+    if (self == (id)kCFNull) return [self hash];
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
+    if (modelMeta->_nsType) return [self hash];
+    
+    NSUInteger value = 0;
+    NSUInteger count = 0;
+    for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
+        if (!propertyMeta->_isKVCCompatible) continue;
+        value ^= [[self valueForKey:NSStringFromSelector(propertyMeta->_getter)] hash];
+        count++;
+    }
+    if (count == 0) value = (long)((__bridge void *)self);
+    return value;
+}
+
+- (BOOL)yy_modelIsEqual:(id)model {
+    if (self == model) return YES;
+    if (![model isMemberOfClass:self.class]) return NO;
+    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
+    if (modelMeta->_nsType) return [self isEqual:model];
+    if ([self hash] != [model hash]) return NO;
+    
+    for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
+        if (!propertyMeta->_isKVCCompatible) continue;
+        id this = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
+        id that = [model valueForKey:NSStringFromSelector(propertyMeta->_getter)];
+        if (this == that) continue;
+        if (this == nil || that == nil) return NO;
+        if (![this isEqual:that]) return NO;
+    }
+    return YES;
+}
+
+- (NSString *)yy_modelDescription {
+    return ModelDescription(self);
+}
+
+@end
+
+
+
+@implementation NSArray (YYModel)
+
++ (NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json {
+    if (!json) return nil;
+    NSArray *arr = nil;
+    NSData *jsonData = nil;
+    if ([json isKindOfClass:[NSArray class]]) {
+        arr = json;
+    } else if ([json isKindOfClass:[NSString class]]) {
+        jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
+    } else if ([json isKindOfClass:[NSData class]]) {
+        jsonData = json;
+    }
+    if (jsonData) {
+        arr = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
+        if (![arr isKindOfClass:[NSArray class]]) arr = nil;
+    }
+    return [self yy_modelArrayWithClass:cls array:arr];
+}
+
++ (NSArray *)yy_modelArrayWithClass:(Class)cls array:(NSArray *)arr {
+    if (!cls || !arr) return nil;
+    NSMutableArray *result = [NSMutableArray new];
+    for (NSDictionary *dic in arr) {
+        if (![dic isKindOfClass:[NSDictionary class]]) continue;
+        NSObject *obj = [cls yy_modelWithDictionary:dic];
+        if (obj) [result addObject:obj];
+    }
+    return result;
+}
+
+@end
+
+
+@implementation NSDictionary (YYModel)
+
++ (NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json {
+    if (!json) return nil;
+    NSDictionary *dic = nil;
+    NSData *jsonData = nil;
+    if ([json isKindOfClass:[NSDictionary class]]) {
+        dic = json;
+    } else if ([json isKindOfClass:[NSString class]]) {
+        jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
+    } else if ([json isKindOfClass:[NSData class]]) {
+        jsonData = json;
+    }
+    if (jsonData) {
+        dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
+        if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
+    }
+    return [self yy_modelDictionaryWithClass:cls dictionary:dic];
+}
+
++ (NSDictionary *)yy_modelDictionaryWithClass:(Class)cls dictionary:(NSDictionary *)dic {
+    if (!cls || !dic) return nil;
+    NSMutableDictionary *result = [NSMutableDictionary new];
+    for (NSString *key in dic.allKeys) {
+        if (![key isKindOfClass:[NSString class]]) continue;
+        NSObject *obj = [cls yy_modelWithDictionary:dic[key]];
+        if (obj) result[key] = obj;
+    }
+    return result;
+}
+
+@end
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.h b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.h
new file mode 100644
index 0000000..6b87458
--- /dev/null
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.h
@@ -0,0 +1,200 @@
+//
+//  YYClassInfo.h
+//  YYModel <https://github.com/ibireme/YYModel>
+//
+//  Created by ibireme on 15/5/9.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Type encoding's type.
+ */
+typedef NS_OPTIONS(NSUInteger, YYEncodingType) {
+    YYEncodingTypeMask       = 0xFF, ///< mask of type value
+    YYEncodingTypeUnknown    = 0, ///< unknown
+    YYEncodingTypeVoid       = 1, ///< void
+    YYEncodingTypeBool       = 2, ///< bool
+    YYEncodingTypeInt8       = 3, ///< char / BOOL
+    YYEncodingTypeUInt8      = 4, ///< unsigned char
+    YYEncodingTypeInt16      = 5, ///< short
+    YYEncodingTypeUInt16     = 6, ///< unsigned short
+    YYEncodingTypeInt32      = 7, ///< int
+    YYEncodingTypeUInt32     = 8, ///< unsigned int
+    YYEncodingTypeInt64      = 9, ///< long long
+    YYEncodingTypeUInt64     = 10, ///< unsigned long long
+    YYEncodingTypeFloat      = 11, ///< float
+    YYEncodingTypeDouble     = 12, ///< double
+    YYEncodingTypeLongDouble = 13, ///< long double
+    YYEncodingTypeObject     = 14, ///< id
+    YYEncodingTypeClass      = 15, ///< Class
+    YYEncodingTypeSEL        = 16, ///< SEL
+    YYEncodingTypeBlock      = 17, ///< block
+    YYEncodingTypePointer    = 18, ///< void*
+    YYEncodingTypeStruct     = 19, ///< struct
+    YYEncodingTypeUnion      = 20, ///< union
+    YYEncodingTypeCString    = 21, ///< char*
+    YYEncodingTypeCArray     = 22, ///< char[10] (for example)
+    
+    YYEncodingTypeQualifierMask   = 0xFF00,   ///< mask of qualifier
+    YYEncodingTypeQualifierConst  = 1 << 8,  ///< const
+    YYEncodingTypeQualifierIn     = 1 << 9,  ///< in
+    YYEncodingTypeQualifierInout  = 1 << 10, ///< inout
+    YYEncodingTypeQualifierOut    = 1 << 11, ///< out
+    YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy
+    YYEncodingTypeQualifierByref  = 1 << 13, ///< byref
+    YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway
+    
+    YYEncodingTypePropertyMask         = 0xFF0000, ///< mask of property
+    YYEncodingTypePropertyReadonly     = 1 << 16, ///< readonly
+    YYEncodingTypePropertyCopy         = 1 << 17, ///< copy
+    YYEncodingTypePropertyRetain       = 1 << 18, ///< retain
+    YYEncodingTypePropertyNonatomic    = 1 << 19, ///< nonatomic
+    YYEncodingTypePropertyWeak         = 1 << 20, ///< weak
+    YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter=
+    YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter=
+    YYEncodingTypePropertyDynamic      = 1 << 23, ///< @dynamic
+};
+
+/**
+ Get the type from a Type-Encoding string.
+ 
+ @discussion See also:
+ https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
+ https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
+ 
+ @param typeEncoding  A Type-Encoding string.
+ @return The encoding type.
+ */
+YYEncodingType YYEncodingGetType(const char *typeEncoding);
+
+
+/**
+ Instance variable information.
+ */
+@interface YYClassIvarInfo : NSObject
+@property (nonatomic, assign, readonly) Ivar ivar;              ///< ivar opaque struct
+@property (nonatomic, strong, readonly) NSString *name;         ///< Ivar's name
+@property (nonatomic, assign, readonly) ptrdiff_t offset;       ///< Ivar's offset
+@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
+@property (nonatomic, assign, readonly) YYEncodingType type;    ///< Ivar's type
+
+/**
+ Creates and returns an ivar info object.
+ 
+ @param ivar ivar opaque struct
+ @return A new object, or nil if an error occurs.
+ */
+- (instancetype)initWithIvar:(Ivar)ivar;
+@end
+
+
+/**
+ Method information.
+ */
+@interface YYClassMethodInfo : NSObject
+@property (nonatomic, assign, readonly) Method method;                  ///< method opaque struct
+@property (nonatomic, strong, readonly) NSString *name;                 ///< method name
+@property (nonatomic, assign, readonly) SEL sel;                        ///< method's selector
+@property (nonatomic, assign, readonly) IMP imp;                        ///< method's implementation
+@property (nonatomic, strong, readonly) NSString *typeEncoding;         ///< method's parameter and return types
+@property (nonatomic, strong, readonly) NSString *returnTypeEncoding;   ///< return value's type
+@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type
+
+/**
+ Creates and returns a method info object.
+ 
+ @param method method opaque struct
+ @return A new object, or nil if an error occurs.
+ */
+- (instancetype)initWithMethod:(Method)method;
+@end
+
+
+/**
+ Property information.
+ */
+@interface YYClassPropertyInfo : NSObject
+@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct
+@property (nonatomic, strong, readonly) NSString *name;           ///< property's name
+@property (nonatomic, assign, readonly) YYEncodingType type;      ///< property's type
+@property (nonatomic, strong, readonly) NSString *typeEncoding;   ///< property's encoding value
+@property (nonatomic, strong, readonly) NSString *ivarName;       ///< property's ivar name
+@property (nullable, nonatomic, assign, readonly) Class cls;      ///< may be nil
+@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *protocols; ///< may nil
+@property (nonatomic, assign, readonly) SEL getter;               ///< getter (nonnull)
+@property (nonatomic, assign, readonly) SEL setter;               ///< setter (nonnull)
+
+/**
+ Creates and returns a property info object.
+ 
+ @param property property opaque struct
+ @return A new object, or nil if an error occurs.
+ */
+- (instancetype)initWithProperty:(objc_property_t)property;
+@end
+
+
+/**
+ Class information for a class.
+ */
+@interface YYClassInfo : NSObject
+@property (nonatomic, assign, readonly) Class cls; ///< class object
+@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
+@property (nullable, nonatomic, assign, readonly) Class metaCls;  ///< class's meta class object
+@property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class
+@property (nonatomic, strong, readonly) NSString *name; ///< class name
+@property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
+@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos; ///< ivars
+@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos; ///< methods
+@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos; ///< properties
+
+/**
+ If the class is changed (for example: you add a method to this class with
+ 'class_addMethod()'), you should call this method to refresh the class info cache.
+ 
+ After called this method, `needUpdate` will returns `YES`, and you should call 
+ 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
+ */
+- (void)setNeedUpdate;
+
+/**
+ If this method returns `YES`, you should stop using this instance and call
+ `classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
+ 
+ @return Whether this class info need update.
+ */
+- (BOOL)needUpdate;
+
+/**
+ Get the class info of a specified Class.
+ 
+ @discussion This method will cache the class info and super-class info
+ at the first access to the Class. This method is thread-safe.
+ 
+ @param cls A class.
+ @return A class info, or nil if an error occurs.
+ */
++ (nullable instancetype)classInfoWithClass:(Class)cls;
+
+/**
+ Get the class info of a specified Class.
+ 
+ @discussion This method will cache the class info and super-class info
+ at the first access to the Class. This method is thread-safe.
+ 
+ @param className A class name.
+ @return A class info, or nil if an error occurs.
+ */
++ (nullable instancetype)classInfoWithClassName:(NSString *)className;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.m
new file mode 100644
index 0000000..16df6d9
--- /dev/null
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYClassInfo.m
@@ -0,0 +1,362 @@
+//
+//  YYClassInfo.m
+//  YYModel <https://github.com/ibireme/YYModel>
+//
+//  Created by ibireme on 15/5/9.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "YYClassInfo.h"
+#import <objc/runtime.h>
+
+YYEncodingType YYEncodingGetType(const char *typeEncoding) {
+    char *type = (char *)typeEncoding;
+    if (!type) return YYEncodingTypeUnknown;
+    size_t len = strlen(type);
+    if (len == 0) return YYEncodingTypeUnknown;
+    
+    YYEncodingType qualifier = 0;
+    bool prefix = true;
+    while (prefix) {
+        switch (*type) {
+            case 'r': {
+                qualifier |= YYEncodingTypeQualifierConst;
+                type++;
+            } break;
+            case 'n': {
+                qualifier |= YYEncodingTypeQualifierIn;
+                type++;
+            } break;
+            case 'N': {
+                qualifier |= YYEncodingTypeQualifierInout;
+                type++;
+            } break;
+            case 'o': {
+                qualifier |= YYEncodingTypeQualifierOut;
+                type++;
+            } break;
+            case 'O': {
+                qualifier |= YYEncodingTypeQualifierBycopy;
+                type++;
+            } break;
+            case 'R': {
+                qualifier |= YYEncodingTypeQualifierByref;
+                type++;
+            } break;
+            case 'V': {
+                qualifier |= YYEncodingTypeQualifierOneway;
+                type++;
+            } break;
+            default: { prefix = false; } break;
+        }
+    }
+
+    len = strlen(type);
+    if (len == 0) return YYEncodingTypeUnknown | qualifier;
+
+    switch (*type) {
+        case 'v': return YYEncodingTypeVoid | qualifier;
+        case 'B': return YYEncodingTypeBool | qualifier;
+        case 'c': return YYEncodingTypeInt8 | qualifier;
+        case 'C': return YYEncodingTypeUInt8 | qualifier;
+        case 's': return YYEncodingTypeInt16 | qualifier;
+        case 'S': return YYEncodingTypeUInt16 | qualifier;
+        case 'i': return YYEncodingTypeInt32 | qualifier;
+        case 'I': return YYEncodingTypeUInt32 | qualifier;
+        case 'l': return YYEncodingTypeInt32 | qualifier;
+        case 'L': return YYEncodingTypeUInt32 | qualifier;
+        case 'q': return YYEncodingTypeInt64 | qualifier;
+        case 'Q': return YYEncodingTypeUInt64 | qualifier;
+        case 'f': return YYEncodingTypeFloat | qualifier;
+        case 'd': return YYEncodingTypeDouble | qualifier;
+        case 'D': return YYEncodingTypeLongDouble | qualifier;
+        case '#': return YYEncodingTypeClass | qualifier;
+        case ':': return YYEncodingTypeSEL | qualifier;
+        case '*': return YYEncodingTypeCString | qualifier;
+        case '^': return YYEncodingTypePointer | qualifier;
+        case '[': return YYEncodingTypeCArray | qualifier;
+        case '(': return YYEncodingTypeUnion | qualifier;
+        case '{': return YYEncodingTypeStruct | qualifier;
+        case '@': {
+            if (len == 2 && *(type + 1) == '?')
+                return YYEncodingTypeBlock | qualifier;
+            else
+                return YYEncodingTypeObject | qualifier;
+        }
+        default: return YYEncodingTypeUnknown | qualifier;
+    }
+}
+
+@implementation YYClassIvarInfo
+
+- (instancetype)initWithIvar:(Ivar)ivar {
+    if (!ivar) return nil;
+    self = [super init];
+    _ivar = ivar;
+    const char *name = ivar_getName(ivar);
+    if (name) {
+        _name = [NSString stringWithUTF8String:name];
+    }
+    _offset = ivar_getOffset(ivar);
+    const char *typeEncoding = ivar_getTypeEncoding(ivar);
+    if (typeEncoding) {
+        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
+        _type = YYEncodingGetType(typeEncoding);
+    }
+    return self;
+}
+
+@end
+
+@implementation YYClassMethodInfo
+
+- (instancetype)initWithMethod:(Method)method {
+    if (!method) return nil;
+    self = [super init];
+    _method = method;
+    _sel = method_getName(method);
+    _imp = method_getImplementation(method);
+    const char *name = sel_getName(_sel);
+    if (name) {
+        _name = [NSString stringWithUTF8String:name];
+    }
+    const char *typeEncoding = method_getTypeEncoding(method);
+    if (typeEncoding) {
+        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
+    }
+    char *returnType = method_copyReturnType(method);
+    if (returnType) {
+        _returnTypeEncoding = [NSString stringWithUTF8String:returnType];
+        free(returnType);
+    }
+    unsigned int argumentCount = method_getNumberOfArguments(method);
+    if (argumentCount > 0) {
+        NSMutableArray *argumentTypes = [NSMutableArray new];
+        for (unsigned int i = 0; i < argumentCount; i++) {
+            char *argumentType = method_copyArgumentType(method, i);
+            NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
+            [argumentTypes addObject:type ? type : @""];
+            if (argumentType) free(argumentType);
+        }
+        _argumentTypeEncodings = argumentTypes;
+    }
+    return self;
+}
+
+@end
+
+@implementation YYClassPropertyInfo
+
+- (instancetype)initWithProperty:(objc_property_t)property {
+    if (!property) return nil;
+    self = [super init];
+    _property = property;
+    const char *name = property_getName(property);
+    if (name) {
+        _name = [NSString stringWithUTF8String:name];
+    }
+    
+    YYEncodingType type = 0;
+    unsigned int attrCount;
+    objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
+    for (unsigned int i = 0; i < attrCount; i++) {
+        switch (attrs[i].name[0]) {
+            case 'T': { // Type encoding
+                if (attrs[i].value) {
+                    _typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
+                    type = YYEncodingGetType(attrs[i].value);
+                    
+                    if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
+                        NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
+                        if (![scanner scanString:@"@\"" intoString:NULL]) continue;
+                        
+                        NSString *clsName = nil;
+                        if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
+                            if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
+                        }
+                        
+                        NSMutableArray *protocols = nil;
+                        while ([scanner scanString:@"<" intoString:NULL]) {
+                            NSString* protocol = nil;
+                            if ([scanner scanUpToString:@">" intoString: &protocol]) {
+                                if (protocol.length) {
+                                    if (!protocols) protocols = [NSMutableArray new];
+                                    [protocols addObject:protocol];
+                                }
+                            }
+                            [scanner scanString:@">" intoString:NULL];
+                        }
+                        _protocols = protocols;
+                    }
+                }
+            } break;
+            case 'V': { // Instance variable
+                if (attrs[i].value) {
+                    _ivarName = [NSString stringWithUTF8String:attrs[i].value];
+                }
+            } break;
+            case 'R': {
+                type |= YYEncodingTypePropertyReadonly;
+            } break;
+            case 'C': {
+                type |= YYEncodingTypePropertyCopy;
+            } break;
+            case '&': {
+                type |= YYEncodingTypePropertyRetain;
+            } break;
+            case 'N': {
+                type |= YYEncodingTypePropertyNonatomic;
+            } break;
+            case 'D': {
+                type |= YYEncodingTypePropertyDynamic;
+            } break;
+            case 'W': {
+                type |= YYEncodingTypePropertyWeak;
+            } break;
+            case 'G': {
+                type |= YYEncodingTypePropertyCustomGetter;
+                if (attrs[i].value) {
+                    _getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
+                }
+            } break;
+            case 'S': {
+                type |= YYEncodingTypePropertyCustomSetter;
+                if (attrs[i].value) {
+                    _setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
+                }
+            } // break; commented for code coverage in next line
+            default: break;
+        }
+    }
+    if (attrs) {
+        free(attrs);
+        attrs = NULL;
+    }
+    
+    _type = type;
+    if (_name.length) {
+        if (!_getter) {
+            _getter = NSSelectorFromString(_name);
+        }
+        if (!_setter) {
+            _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
+        }
+    }
+    return self;
+}
+
+@end
+
+@implementation YYClassInfo {
+    BOOL _needUpdate;
+}
+
+- (instancetype)initWithClass:(Class)cls {
+    if (!cls) return nil;
+    self = [super init];
+    _cls = cls;
+    _superCls = class_getSuperclass(cls);
+    _isMeta = class_isMetaClass(cls);
+    if (!_isMeta) {
+        _metaCls = objc_getMetaClass(class_getName(cls));
+    }
+    _name = NSStringFromClass(cls);
+    [self _update];
+
+    _superClassInfo = [self.class classInfoWithClass:_superCls];
+    return self;
+}
+
+- (void)_update {
+    _ivarInfos = nil;
+    _methodInfos = nil;
+    _propertyInfos = nil;
+    
+    Class cls = self.cls;
+    unsigned int methodCount = 0;
+    Method *methods = class_copyMethodList(cls, &methodCount);
+    if (methods) {
+        NSMutableDictionary *methodInfos = [NSMutableDictionary new];
+        _methodInfos = methodInfos;
+        for (unsigned int i = 0; i < methodCount; i++) {
+            YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
+            if (info.name) methodInfos[info.name] = info;
+        }
+        free(methods);
+    }
+    unsigned int propertyCount = 0;
+    objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
+    if (properties) {
+        NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
+        _propertyInfos = propertyInfos;
+        for (unsigned int i = 0; i < propertyCount; i++) {
+            YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
+            if (info.name) propertyInfos[info.name] = info;
+        }
+        free(properties);
+    }
+    
+    unsigned int ivarCount = 0;
+    Ivar *ivars = class_copyIvarList(cls, &ivarCount);
+    if (ivars) {
+        NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
+        _ivarInfos = ivarInfos;
+        for (unsigned int i = 0; i < ivarCount; i++) {
+            YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
+            if (info.name) ivarInfos[info.name] = info;
+        }
+        free(ivars);
+    }
+    
+    if (!_ivarInfos) _ivarInfos = @{};
+    if (!_methodInfos) _methodInfos = @{};
+    if (!_propertyInfos) _propertyInfos = @{};
+    
+    _needUpdate = NO;
+}
+
+- (void)setNeedUpdate {
+    _needUpdate = YES;
+}
+
+- (BOOL)needUpdate {
+    return _needUpdate;
+}
+
++ (instancetype)classInfoWithClass:(Class)cls {
+    if (!cls) return nil;
+    static CFMutableDictionaryRef classCache;
+    static CFMutableDictionaryRef metaCache;
+    static dispatch_once_t onceToken;
+    static dispatch_semaphore_t lock;
+    dispatch_once(&onceToken, ^{
+        classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+        metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+        lock = dispatch_semaphore_create(1);
+    });
+    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+    YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
+    if (info && info->_needUpdate) {
+        [info _update];
+    }
+    dispatch_semaphore_signal(lock);
+    if (!info) {
+        info = [[YYClassInfo alloc] initWithClass:cls];
+        if (info) {
+            dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+            CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
+            dispatch_semaphore_signal(lock);
+        }
+    }
+    return info;
+}
+
++ (instancetype)classInfoWithClassName:(NSString *)className {
+    Class cls = NSClassFromString(className);
+    return [self classInfoWithClass:cls];
+}
+
+@end
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYModel.h b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYModel.h
new file mode 100644
index 0000000..e1154ee
--- /dev/null
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/Venders/YYModel/YYModel.h
@@ -0,0 +1,22 @@
+//
+//  YYModel.h
+//  YYModel <https://github.com/ibireme/YYModel>
+//
+//  Created by ibireme on 15/5/10.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <Foundation/Foundation.h>
+
+#if __has_include(<YYModel/YYModel.h>)
+FOUNDATION_EXPORT double YYModelVersionNumber;
+FOUNDATION_EXPORT const unsigned char YYModelVersionString[];
+#import <YYModel/NSObject+YYModel.h>
+#import <YYModel/YYClassInfo.h>
+#else
+#import "NSObject+YYModel.h"
+#import "YYClassInfo.h"
+#endif
diff --git a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/ViewController.m b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/ViewController.m
index a6a7de9..510811b 100644
--- a/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/ViewController.m
+++ b/Demo/EZOpensdk_iOS_4.15.1_build20201104/Demo/EZOpenSDKDemo/ViewController.m
@@ -11,6 +11,7 @@
 #import "DDKit.h"
 #import "EZSDK.h"
 #import "MBProgressHUD.h"
+#import "EZCameraInfo.h"
 
 @interface ViewController ()
 @property (weak, nonatomic) IBOutlet UIButton *ddnsDemoBtn;
@@ -55,10 +56,10 @@
 //     */
 //    [self performSegueWithIdentifier:@"go2CameraList" sender:nil];
     
-    [EZSDK setHDlAccessToken:@"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJkODQ5ODllZDMzODQ0ZmFiYWViMWM4YTRlMDlmZDFlMCIsInJvbGUiOiIiLCJoZWFkZXJQcmVmaXgiOiJCZWFyZXIgIiwidXNlckFjY291bnQiOiIxODgyNDg2NDE0MyIsInRlbmFudElkIjoiMjAiLCJ1c2VyVHlwZSI6IlVTRVJfQyIsInRva2VuVHlwZSI6ImFjY2Vzc190b2tlbiIsInVzZXJOYW1lIjoiTEUwMDAiLCJhcHBsaWNhdGlvbklkIjoiMCIsInVzZXJJZCI6IjEzMjg4ODYyNzMwMDM4NTU4NzQiLCJleHAiOjE2MTk1MDczMDEsIm5iZiI6MTYxOTUwMDEwMX0.dS-Lme85XjrHK6fRC1_9hzednq9YLz6gtaaW-50gX3F2eidl3XDa8AP17KrCNhxkAMrOBRpZ0sxqGM7y-WPpUy0p_ytiTt5F1k8MR--Q7njpxxUMttuGzKEmj4Xk1G1Mx55zVlzvIBOHIFm44upWoIObW34nbMjnr8tIa2H7FEY" refreshToken:@"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI4NmMwYmI1MGQ5N2Q0OGU4OWIzMmRlZDE5NjdmOGE5MiIsImhlYWRlclByZWZpeCI6IkJlYXJlciAiLCJ0ZW5hbnRJZCI6IjIwIiwidG9rZW5UeXBlIjoicmVmcmVzaF90b2tlbiIsImFwcGxpY2F0aW9uSWQiOiIwIiwidXNlcklkIjoiMTMyODg4NjI3MzAwMzg1NTg3NCIsImV4cCI6MTYyMDEwNDkwMSwibmJmIjoxNjE5NTAwMTAxfQ.AgejbuQdmsc7UItIGtcDoWAepuHo56amU7dhmbndj-0TlbmFPOPQbIxvs8nEAQeCAFavrHctWGCypaW8MTvmYTOISbf4n2-Jk8wQX5xJdwEzNI0kJrTeIY1yejo9c12LT1ZL6y-8WkDjRKATDOCrrfy-bdsqFo78VEuUtp_tFeQ"];
+    [EZSDK setHDlAccessToken:@"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIyYTAwZGRmOTNjMGY0YzlhYjljNjU2M2VhMDJjZjhmMyIsImNvbXBhbnlJZCI6IjAiLCJyb2xlIjoiIiwiaGVhZGVyUHJlZml4IjoiQmVhcmVyICIsInVzZXJBY2NvdW50Ijoid3hyIiwidGVuYW50SWQiOiIyMCIsInVzZXJUeXBlIjoiVVNFUl9DIiwidG9rZW5UeXBlIjoiYWNjZXNzX3Rva2VuIiwidXNlck5hbWUiOiJrYWVkZSIsIm9wZW5BcHBsaWNhdGlvbklkIjoiMCIsInVzZXJJZCI6IjEzOTIwMzU1NjgyMDQ0MjMxNjkiLCJleHAiOjE2MjU2NjA0NjQsIm5iZiI6MTYyNTY1MzI2NH0.I4YfZQqm1p1SwJQbNWyUEOWXCqpYCWQdmAMOR-xlOMJ0pYFh3_nyjPBiWypTTMgy5nTpj7IqUM1bHwHWGsDEInF4Bl6trxrgOE39Toj-aY1UJcViYhx7e3E3ChrlXptVfKtk3cVEtDlFkMdHdHiJi-6OZox4KOz_AallI8lFIlo" refreshToken:@"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI1ZjdmOGFkY2I3MGU0NzYwOWE0NTcxOTZmOTAyOTY1OSIsImNvbXBhbnlJZCI6IjAiLCJoZWFkZXJQcmVmaXgiOiJCZWFyZXIgIiwidGVuYW50SWQiOiIyMCIsInRva2VuVHlwZSI6InJlZnJlc2hfdG9rZW4iLCJvcGVuQXBwbGljYXRpb25JZCI6IjAiLCJ1c2VySWQiOiIxMzkyMDM1NTY4MjA0NDIzMTY5IiwiZXhwIjoxNjI2MjU4MDY0LCJuYmYiOjE2MjU2NTMyNjR9.DB1pGaM6xtpQiP_KvaAHbWDZtxjLXZwJCgFfrp_XA0bnV8wMC8SE7K_uoP79c97WGqcmpHJVY-x8NCVJneGpIKN2oSCvX0Sn0uAttqni4zbVjmErC2AmpONJwWY27GYjHk4LFri03p38D-5zlULFo3ITtN3Il2aJOjVOpyNCcuI"];
     
     
-    [EZSDK setRequestHttpsHostAndPlatform:@"https://test-gz.hdlcontrol.com" platform:2];
+    [EZSDK setRequestHttpsHostAndPlatform:@"https://test-gz.hdlcontrol.com" platform:1 homeId:@"1396717478877241345"];
     
     
     
@@ -77,15 +78,54 @@
     }];
 }
 
+
+
 - (IBAction)logout:(id)sender
 {
-   
+//    [[GlobalKit shareKit] setAccessToken:@"ra.a5bfkhhx7ycscsj41if7l0cf9ytfhv5q-9keuxvphmn-1fvjt6p-jugtyy8sr"];
+    [EZSDK setHDlAccessToken:@"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI2Zjk1ZTEwZWIwNjA0ZjNiYTdmNTc0ZGUyM2QxYmNmZiIsImNvbXBhbnlJZCI6IjAiLCJyb2xlIjoiIiwiaGVhZGVyUHJlZml4IjoiQmVhcmVyICIsInVzZXJBY2NvdW50Ijoid3hyIiwidGVuYW50SWQiOiIyMCIsInVzZXJUeXBlIjoiVVNFUl9DIiwidG9rZW5UeXBlIjoiYWNjZXNzX3Rva2VuIiwidXNlck5hbWUiOiJrYWVkZSIsIm9wZW5BcHBsaWNhdGlvbklkIjoiMCIsInVzZXJJZCI6IjEzOTIwMzU1NjgyMDQ0MjMxNjkiLCJleHAiOjE2MjU3MTY3NjAsIm5iZiI6MTYyNTcwOTU2MH0.C6w0mb0YiNhqQfLPscXiNVh_DOsbza_fubUbn_T-W04L3R7egi7-Gv_iifdfvh4XTU10rEdVl6FLXKxt3JJvo2x_sjBQLkWRQINMVl1qLOz9cMew79_aykXOwl8mdroYs9SKBd90qyM2lZaA91sD4H0HMVVyc_D2TEcG4XJzSBM" refreshToken:@"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI1M2FlMzg3NDhmNjU0MzE1OTM0MTQ0OWQyYmQ0NjE0NiIsImNvbXBhbnlJZCI6IjAiLCJoZWFkZXJQcmVmaXgiOiJCZWFyZXIgIiwidGVuYW50SWQiOiIyMCIsInRva2VuVHlwZSI6InJlZnJlc2hfdG9rZW4iLCJvcGVuQXBwbGljYXRpb25JZCI6IjAiLCJ1c2VySWQiOiIxMzkyMDM1NTY4MjA0NDIzMTY5IiwiZXhwIjoxNjI2MzE0MzYwLCJuYmYiOjE2MjU3MDk1NjB9.AZlG8jO8lFDcj5dfoY0rZsDfglGdeyLuSImzMw1enHWfAacjkIof0vXQ_qJG9Q-6qxyXXbPu_xrd0DhkGNFeHJ4WFL0iiYgDP51sJuUdKrQklUCSC6T7ZjIW0GSVmvOW4GCw0s6L51bVT_rkdrusVD4rDnOtJwWqXTUfyNanmlk"];
+    
+    
+    [EZSDK setRequestHttpsHostAndPlatform:@"https://test-gz.hdlcontrol.com" platform:1 homeId:@"1396717478877241345"];
+
+    
+    __weak MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
+    hud.labelText = NSLocalizedString(@"ad_adding_msg", @"璇风◢鍊�...");
+    [EZHttpUtil.sharedManager getChildToken:^(NSString *accessToken) {
+        [hud hide:YES];
+        if(accessToken != NULL && ![accessToken isEqual:@""]){
+            NSLog(@"accessToken HDL:%@",accessToken);
+            [[GlobalKit shareKit] setAccessToken:accessToken];
+            
+            [EZSDK PlayWithDeviceSerial:@"F44133728"];
+
+            
+        }
+    }];
+    
 //    [EZOPENSDK logout:^(NSError *error) {
 //    }];
     
 
 }
 
+-(void)getEzDeviceInfo:(NSString *)deviceSerial{
+    
+    //鑾峰彇璁惧鍒楄〃鎺ュ彛
+    [EZOpenSDK getDeviceInfo:deviceSerial completion:^(EZDeviceInfo *deviceInfo, NSError *error) {
+        if(error)
+        {
+            return;
+        }
+        if (deviceInfo) {
+            [EZSDK Play:deviceInfo];
+        }
+    
+    }];
+        
+//    [EZOPENSDK :deviceSerial];
+}
+
 - (void)handleTheError:(NSError *)error
 {
     if (!error)
diff --git a/EZSDK.IOS/EZSDK.IOS/ApiDefinition.cs b/EZSDK.IOS/EZSDK.IOS/ApiDefinition.cs
index 894ab99..0046eca 100644
--- a/EZSDK.IOS/EZSDK.IOS/ApiDefinition.cs
+++ b/EZSDK.IOS/EZSDK.IOS/ApiDefinition.cs
@@ -1,59 +1,148 @@
 锘縰sing System;
-
-using ObjCRuntime;
 using Foundation;
-using UIKit;
+using ObjCRuntime;
 
 namespace EZSDK.IOS
 {
-	// @interface EZSDK : NSObject
-	[BaseType (typeof(NSObject))]
-	interface EZSDK
-	{
-		// +(BOOL)initLibWithAppKey:(NSString *)appKey globalAppKey:(NSString *)globalAppKey;
-		[Static]
-		[Export ("initLibWithAppKey:globalAppKey:")]
-		bool InitLibWithAppKey (string appKey, string globalAppKey);
+    // @interface EZDeviceInfo : NSObject
+    [BaseType(typeof(NSObject))]
+    interface EZDeviceInfo
+    {
+        // @property (nonatomic, strong) NSArray * cameraInfo;
+        [Export("cameraInfo", ArgumentSemantic.Strong)]
+        //[Verify(StronglyTypedNSArray)]
+        NSArray CameraInfo { get; set; }
 
-		// +(void)setEZAccessToken:(NSString *)accessToken;
-		[Static]
-		[Export ("setEZAccessToken:")]
-		void SetEZAccessToken (string accessToken);
+        // @property (nonatomic) NSInteger cameraNum;
+        [Export("cameraNum")]
+        int CameraNum { get; set; }
 
-		// +(void)setHDlAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken;
-		[Static]
-		[Export ("setHDlAccessToken:refreshToken:")]
-		void SetHDlAccessToken (string accessToken, string refreshToken);
+        // @property (nonatomic) NSInteger defence;
+        [Export("defence")]
+        int Defence { get; set; }
 
-		// +(void)setRequestHttpsHostAndPlatform:(NSString *)requestHttpsHost platform:(int)platform;
-		[Static]
-		[Export("setRequestHttpsHostAndPlatform:platform:")]
-		void SetRequestHttpsHostAndPlatform(string requestHttpsHost, int platform);
+        // @property (nonatomic) NSInteger detectorNum;
+        [Export("detectorNum")]
+        int DetectorNum { get; set; }
 
-		// +(void)go2EZvizMonitor;
-		[Static]
-		[Export ("go2EZvizMonitor")]
-		void Go2EZvizMonitor ();
+        // @property (nonatomic, strong) NSArray * detectorInfo;
+        [Export("detectorInfo", ArgumentSemantic.Strong)]
+        //[Verify(StronglyTypedNSArray)]
+        NSArray DetectorInfo { get; set; }
 
-		// +(void)addEzvizMonitor;
-		[Static]
-		[Export ("addEzvizMonitor")]
-		void AddEzvizMonitor ();
+        // @property (copy, nonatomic) NSString * deviceCover;
+        [Export("deviceCover")]
+        string DeviceCover { get; set; }
 
-		// +(void)Play:(NSObject *)deviceInfo;
-		[Static]
-		[Export ("Play:")]
-		void Play (NSObject deviceInfo);
+        // @property (copy, nonatomic) NSString * deviceName;
+        [Export("deviceName")]
+        string DeviceName { get; set; }
 
-		// +(void)setting:(NSObject *)deviceInfo;
-		[Static]
-		[Export ("setting:")]
-		void Setting (NSObject deviceInfo);
+        // @property (copy, nonatomic) NSString * deviceSerial;
+        [Export("deviceSerial")]
+        string DeviceSerial { get; set; }
 
-		// +(void)playBackVideo:(NSObject *)deviceInfo;
-		[Static]
-		[Export ("playBackVideo:")]
-		void PlayBackVideo (NSObject deviceInfo);
-	}
+        // @property (copy, nonatomic) NSString * deviceType;
+        [Export("deviceType")]
+        string DeviceType { get; set; }
+
+        // @property (copy, nonatomic) NSString * deviceVersion;
+        [Export("deviceVersion")]
+        string DeviceVersion { get; set; }
+
+        // @property (nonatomic) BOOL isEncrypt;
+        [Export("isEncrypt")]
+        bool IsEncrypt { get; set; }
+
+        // @property (nonatomic) NSInteger status;
+        [Export("status")]
+        int Status { get; set; }
+
+        // @property (nonatomic) NSInteger isSupportTalk;
+        [Export("isSupportTalk")]
+        int IsSupportTalk { get; set; }
+
+        // @property (nonatomic) BOOL isSupportPTZ;
+        [Export("isSupportPTZ")]
+        bool IsSupportPTZ { get; set; }
+
+        // @property (nonatomic) BOOL isSupportZoom;
+        [Export("isSupportZoom")]
+        bool IsSupportZoom { get; set; }
+
+        // @property (nonatomic) BOOL isSupportAudioOnOff;
+        [Export("isSupportAudioOnOff")]
+        bool IsSupportAudioOnOff { get; set; }
+
+        // @property (nonatomic) BOOL isSupportMirrorCenter;
+        [Export("isSupportMirrorCenter")]
+        bool IsSupportMirrorCenter { get; set; }
+
+        // @property (nonatomic) BOOL isSupportSoundWave;
+        [Export("isSupportSoundWave")]
+        bool IsSupportSoundWave { get; set; }
+
+        // @property (copy, nonatomic) NSString * category;
+        [Export("category")]
+        string Category { get; set; }
+
+        // @property (nonatomic, strong) NSDate * addTime;
+        [Export("addTime", ArgumentSemantic.Strong)]
+        NSDate AddTime { get; set; }
+    }
+
+    // @interface EZSDK : NSObject
+    [BaseType(typeof(NSObject))]
+    interface EZSDK
+    {
+        // +(BOOL)initLibWithAppKey:(NSString *)appKey globalAppKey:(NSString *)globalAppKey;
+        [Static]
+        [Export("initLibWithAppKey:globalAppKey:")]
+        bool InitLibWithAppKey(string appKey, string globalAppKey);
+
+        // +(void)setEZAccessToken:(NSString *)accessToken;
+        [Static]
+        [Export("setEZAccessToken:")]
+        void SetEZAccessToken(string accessToken);
+
+        // +(void)setHDlAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken;
+        [Static]
+        [Export("setHDlAccessToken:refreshToken:")]
+        void SetHDlAccessToken(string accessToken, string refreshToken);
+
+        // +(void)setRequestHttpsHostAndPlatform:(NSString *)requestHttpsHost platform:(int)platform homeId:(NSString *)homeId;
+        [Static]
+        [Export("setRequestHttpsHostAndPlatform:platform:homeId:")]
+        void SetRequestHttpsHostAndPlatform(string requestHttpsHost, int platform, string homeId);
+
+        // +(void)go2EZvizMonitor;
+        [Static]
+        [Export("go2EZvizMonitor")]
+        void Go2EZvizMonitor();
+
+        // +(void)addEzvizMonitor;
+        [Static]
+        [Export("addEzvizMonitor")]
+        void AddEzvizMonitor();
+
+        // +(void)Play:(EZDeviceInfo *)deviceInfo;
+        [Static]
+        [Export("Play:")]
+        void Play(EZDeviceInfo deviceInfo);
+
+        // +(void)PlayWithDeviceSerial:(NSString *)deviceSerial;
+        [Static]
+        [Export("PlayWithDeviceSerial:")]
+        void PlayWithDeviceSerial(string deviceSerial);
+
+        // +(void)setting:(EZDeviceInfo *)deviceInfo;
+        [Static]
+        [Export("setting:")]
+        void Setting(EZDeviceInfo deviceInfo);
+
+        // +(void)playBackVideo:(EZDeviceInfo *)deviceInfo;
+        [Static]
+        [Export("playBackVideo:")]
+        void PlayBackVideo(EZDeviceInfo deviceInfo);
+    }
 }
-
diff --git a/EZSDK.IOS/EZSDK.IOS/Library/libEZSDK.a b/EZSDK.IOS/EZSDK.IOS/Library/libEZSDK.a
index 9efe895..dcd6b46 100644
--- a/EZSDK.IOS/EZSDK.IOS/Library/libEZSDK.a
+++ b/EZSDK.IOS/EZSDK.IOS/Library/libEZSDK.a
Binary files differ
diff --git a/EZSDK.IOS/EZSDK.IOS/Properties/AssemblyInfo.cs b/EZSDK.IOS/EZSDK.IOS/Properties/AssemblyInfo.cs
index 8f1a669..7cbedfc 100644
--- a/EZSDK.IOS/EZSDK.IOS/Properties/AssemblyInfo.cs
+++ b/EZSDK.IOS/EZSDK.IOS/Properties/AssemblyInfo.cs
@@ -25,7 +25,7 @@
 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
 
-[assembly: AssemblyVersion("1.3.1")]
+[assembly: AssemblyVersion("1.4.2")]
 
 // The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
diff --git a/EZSDK/EZSDK/DeviceInfo.h b/EZSDK/EZSDK/DeviceInfo.h
index 87b2fb9..294fbff 100644
--- a/EZSDK/EZSDK/DeviceInfo.h
+++ b/EZSDK/EZSDK/DeviceInfo.h
@@ -6,17 +6,11 @@
 //
 
 #import <Foundation/Foundation.h>
+#import "EZDeviceInfo.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface DeviceInfo : NSObject
-
-@property(nonatomic,strong)NSString *DeviceName;
-@property(nonatomic,strong)NSString *DeviceSerial;
-@property(nonatomic,assign)int DeviceNum;  //cameraNum
-@property(nonatomic,assign)int DeviceCameraInfoListSize;
-@property(nonatomic,strong)NSObject* RealObject;
-@property(nonatomic,strong)NSArray *cameraInfo;
+@interface DeviceInfo :EZDeviceInfo
 
 
 @end
diff --git a/EZSDK/EZSDK/EZ/Global/EZHttpUtil.m b/EZSDK/EZSDK/EZ/Global/EZHttpUtil.m
index 29b7426..6c2236e 100644
--- a/EZSDK/EZSDK/EZ/Global/EZHttpUtil.m
+++ b/EZSDK/EZSDK/EZ/Global/EZHttpUtil.m
@@ -13,9 +13,9 @@
 
 #define TestRequestHttpsHost @"https://test-gz.hdlcontrol.com"
 #pragma mark API
-#define API_POST_EZ_AddDevice @"/home-wisdom/platform/childAddDevice"
-#define API_POST_EZ_GetChildToken @"/home-wisdom/platform/childToken"
-#define API_POST_EZ_ChildDelDevice @"/home-wisdom/platform/childDelDevice"
+#define API_POST_EZ_AddDevice @"/home-wisdom/platform/yingshi/child/addDevice"
+#define API_POST_EZ_GetChildToken @"/home-wisdom/platform/yingshi/child/token"
+#define API_POST_EZ_ChildDelDevice @"/home-wisdom/platform/yingshi/child/deleteDevice"
 #define API_POST_EZ_RefreshToken @"/smart-footstone/member/oauth/login"
 
 
@@ -51,13 +51,15 @@
     //2.璁剧疆璇锋眰鍙傛暟
     NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
     [parameters setValue: [NSString stringWithFormat:@"%d", [GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
     parameters = [self GetSignRequestDictionary:parameters];
     
     [self requestHttpsPost:API_POST_EZ_GetChildToken parameters:parameters completion:^(ResponseData *responseData) {
         if (block) {
             NSString * token = @"";
             if(responseData.success){
-                token = responseData.data[@"accessToken"];
+//                token = responseData.data[@"accessToken"];
+                token = [NSString stringWithFormat:@"%@",responseData.data];
             }
             block(token);
         }
@@ -84,9 +86,11 @@
     [parameters setValue:deviceSerial forKey:@"deviceSerial"];
     [parameters setValue:verifyCode forKey:@"validateCode"];
     [parameters setValue: [NSString stringWithFormat:@"%d",[GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
+    
     parameters = [self GetSignRequestDictionary:parameters];
     
-   [self requestHttpsPost:API_POST_EZ_AddDevice parameters:parameters completion:^(ResponseData *responseData) {
+    [self requestHttpsPost:API_POST_EZ_AddDevice parameters:parameters completion:^(ResponseData *responseData) {
         if (completion) {
             completion (responseData);
         }
@@ -108,6 +112,8 @@
     NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
     [parameters setValue:deviceSerial forKey:@"deviceSerial"];
     [parameters setValue: [NSString stringWithFormat:@"%d",[GlobalKit shareKit].hdlPlatform] forKey:@"platform"];
+    [parameters setValue:[GlobalKit shareKit].hdlHomeId forKey:@"homeId"];
+    
     parameters = [self GetSignRequestDictionary:parameters];
     
     [self requestHttpsPost:API_POST_EZ_ChildDelDevice parameters:parameters completion:^(ResponseData *responseData) {
@@ -251,7 +257,8 @@
     NSString *newString = @"";
     for(NSString *key in sortKeyArray){
         if(params[key] != NULL){
-            NSString *valueStr = params[key];
+            //Key瀵瑰簲鐨剉alue寮鸿浆涓篘SString
+            NSString *valueStr = [NSString stringWithFormat:@"%@",[params objectForKey:key]];
             //妫�娴嬪綋鍓嶅弬鏁版槸鍚﹂渶瑕佸弬涓庢牎楠�
             if([self IfValueNeedSign:valueStr]){
                 newString = [newString stringByAppendingString:[NSString stringWithFormat:@"%@=%@&", key,valueStr]];
@@ -311,7 +318,10 @@
     if (( [self stringIsNullOrEmpty:valueStr])//鍒ょ┖瀛楃
         || ([[valueStr substringToIndex:1] isEqual:@"{"])//鍒ゆ柇鏄惁涓哄璞�
         || ([[valueStr substringToIndex:1] isEqual:@"["])//鍒ゆ柇鏄惁涓烘暟缁�
+        || ([[valueStr substringToIndex:1] isEqual:@"("])//鍒ゆ柇鏄惁涓烘暟缁�
         ) {
+        
+//        HDLSDKLog(@"涓嶆牎楠�: %@",valueStr);
         return false;
     }
     return true;
@@ -319,3 +329,9 @@
 
 
 @end
+
+
+#pragma mark - 淇敼璁板綍
+//2021-07-07
+//V1.1.3
+//1.鏇挎崲涓烘柊鎺ュ彛锛屾牴鎹甴omeId娉ㄥ唽钀ょ煶瀛愯处鍙锋柟妗堛��
diff --git a/EZSDK/EZSDK/EZ/Global/GlobalKit.h b/EZSDK/EZSDK/EZ/Global/GlobalKit.h
index 1ede585..d8917f4 100644
--- a/EZSDK/EZSDK/EZ/Global/GlobalKit.h
+++ b/EZSDK/EZSDK/EZ/Global/GlobalKit.h
@@ -22,6 +22,7 @@
 @property (nonatomic, copy) NSString *GlobalRequestHttpsHost;
 @property (nonatomic, copy) NSString *hdlAccessToken;
 @property (nonatomic, copy) NSString *hdlRefreshToken;
+@property (nonatomic, copy) NSString *hdlHomeId;
 
 @property (nonatomic, copy) NSString *accessToken;
 @property (nonatomic, copy) NSString *deviceSerialNo;  //璁惧搴忓垪鍙�
diff --git a/EZSDK/EZSDK/EZ/Global/GlobalKit.m b/EZSDK/EZSDK/EZ/Global/GlobalKit.m
index 4a06059..c58d0ad 100644
--- a/EZSDK/EZSDK/EZ/Global/GlobalKit.m
+++ b/EZSDK/EZSDK/EZ/Global/GlobalKit.m
@@ -66,7 +66,7 @@
     _GlobalRequestHttpsHost = GlobalRequestHttpsHost;
 }
 
-- (void)sethdlPlatform:(int )hdlPlatform
+- (void)sethdlPlatform:(int)hdlPlatform
 {
     _hdlPlatform = hdlPlatform;
 }
@@ -74,7 +74,7 @@
 - (void)clearSession
 {
     _accessToken = nil;
-    _hdlRefreshToken = nil;
+    _hdlAccessToken = nil;
     _hdlRefreshToken = nil;
     [[NSUserDefaults standardUserDefaults] removeObjectForKey:EZOpenSDKAccessToken];
     [[NSUserDefaults standardUserDefaults] synchronize];
diff --git a/EZSDK/EZSDK/EZ/TableViewCells/DeviceListCell.m b/EZSDK/EZSDK/EZ/TableViewCells/DeviceListCell.m
index 935f895..abf9966 100644
--- a/EZSDK/EZSDK/EZ/TableViewCells/DeviceListCell.m
+++ b/EZSDK/EZSDK/EZ/TableViewCells/DeviceListCell.m
@@ -44,8 +44,9 @@
 //    }];
 //    [EZOPENSDK cap]
     
-    //2021-05-08 闅愯棌褰曞儚鎸夐挳
-    self.recordButton.hidden = YES;
+//    //2021-05-08 闅愯棌褰曞儚鎸夐挳
+//    //2021-07-07 鍙栨秷闅愯棌
+//    self.recordButton.hidden = YES;
     
     self.messageButton.hidden = NO;
     self.settingButton.hidden = NO;
diff --git a/EZSDK/EZSDK/EZSDK.h b/EZSDK/EZSDK/EZSDK.h
index d9b3fe5..9325728 100644
--- a/EZSDK/EZSDK/EZSDK.h
+++ b/EZSDK/EZSDK/EZSDK.h
@@ -6,7 +6,7 @@
 //
 
 #import <Foundation/Foundation.h>
-
+#import "EZDeviceInfo.h"
 
 @interface EZSDK : NSObject
 /**
@@ -21,11 +21,11 @@
 /**
  璁剧疆HDLSDK鐨刟ccessToken
  */
-+(void)setHDlAccessToken:(NSString *) accessToken refreshToken:(NSString *) refreshToken;
++(void)setHDlAccessToken:(NSString *)accessToken refreshToken:(NSString *) refreshToken;
 /**
  璁剧疆SDK鐨勬渤涓滄帴鍙g殑requestHttpsHost鍜屽钩鍙� 鏍囪瘑锛�1.on+(榛樿) 2.evoyo
  */
-+(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int) platform;
++(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int)platform homeId:(NSString *)homeId;
 
 /**
  鐩存帴璺宠浆鍒拌悿鐭虫憚鍍忓ご鍒楄〃
@@ -38,14 +38,17 @@
 /**
  鏌ョ湅瑙嗛鐩戞帶鐩存挱
  */
-+(void)Play:(NSObject*)deviceInfo;
++(void)Play:(EZDeviceInfo*)deviceInfo;
+/// 鎸囧畾搴忓垪鍙� 鏌ョ湅瑙嗛鐩戞帶鐩存挱
+/// @param deviceSerial 搴忓垪鍙�
++(void)PlayWithDeviceSerial:(NSString *)deviceSerial;
 /**
  鎵撳紑鎽勫儚澶磋缃〉闈�
  */
-+(void)setting:(NSObject*)deviceInfo;
++(void)setting:(EZDeviceInfo*)deviceInfo;
 /**
  鍥炴斁鎾斁鍘嗗彶
  */
-+(void)playBackVideo:(NSObject*)deviceInfo;
++(void)playBackVideo:(EZDeviceInfo*)deviceInfo;
 
 @end
diff --git a/EZSDK/EZSDK/EZSDK.m b/EZSDK/EZSDK/EZSDK.m
index 57ebd9c..cfb414f 100644
--- a/EZSDK/EZSDK/EZSDK.m
+++ b/EZSDK/EZSDK/EZSDK.m
@@ -74,9 +74,10 @@
 /**
  璁剧疆SDK鐨勬渤涓滄帴鍙g殑requestHttpsHost鍜屽钩鍙� 鏍囪瘑锛�1.on+(榛樿) 2.evoyo
  */
-+(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int) platform{
++(void)setRequestHttpsHostAndPlatform:(NSString *) requestHttpsHost platform:(int)platform homeId:(NSString *)homeId{
     [[GlobalKit shareKit] setGlobalRequestHttpsHost:requestHttpsHost];
     [[GlobalKit shareKit] setHdlPlatform:platform];
+    [[GlobalKit shareKit] setHdlHomeId:homeId];
 }
 
 //鑾峰彇褰撳墠灞忓箷鏄剧ず鐨剉iewcontroller   (杩欓噷闈㈣幏鍙栫殑鐩稿綋浜巖ootViewController)
@@ -138,22 +139,40 @@
 /**
  鏌ョ湅瑙嗛鐩戞帶鐩存挱
  */
-+(void)Play:(NSObject*)deviceInfo
++(void)Play:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *addDeviceStoryBoard = [UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZLivePlayViewController *rootViewController = [addDeviceStoryBoard instantiateViewControllerWithIdentifier:@"EZLivePlayViewController"];
     //        NSLog(@"play--iphone--rootViewController");
     rootViewController.deviceInfo=(EZDeviceInfo *)deviceInfo;
     NSLog(@"play--iphone--deviceName -%@",rootViewController.deviceInfo.deviceName);
-    //        rootViewController.cameraIndex=0;
+//            rootViewController.cameraIndex=0;
     [[self getCurrentVC] setNavigationBarHidden:NO];
     [[self getCurrentVC] pushViewController:rootViewController animated:YES];
+    
+    
+}
+
+/// 鎸囧畾搴忓垪鍙锋挱鏀�
+/// @param deviceSerial 搴忓垪鍙�
++(void)PlayWithDeviceSerial:(NSString *)deviceSerial{
+    //鑾峰彇璁惧鍒楄〃鎺ュ彛
+    [EZOpenSDK getDeviceInfo:deviceSerial completion:^(EZDeviceInfo *deviceInfo, NSError *error) {
+        if(error)
+        {
+            NSLog(@"EZ 鏌ヨ璁惧淇℃伅澶辫触");
+            return;
+        }
+        if (deviceInfo) {
+            [self Play:deviceInfo];
+        }
+    }];
 }
 
 /**
  鎵撳紑鎽勫儚澶磋缃〉闈�
  */
-+(void)setting:(NSObject*)deviceInfo
++(void)setting:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *settingStoryBoard=[UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZSettingViewController *settingVC=[settingStoryBoard instantiateViewControllerWithIdentifier:@"EZSettingViewController"];
@@ -165,7 +184,7 @@
 /**
  鍥炴斁鎾斁鍘嗗彶
  */
-+(void)playBackVideo:(NSObject*)deviceInfo
++(void)playBackVideo:(EZDeviceInfo*)deviceInfo
 {
     UIStoryboard *playBackStoryBoard=[UIStoryboard storyboardWithName:@"EZMain" bundle:nil];
     EZPlaybackViewController *playBackVC=[playBackStoryBoard instantiateViewControllerWithIdentifier:@"EZPlaybackViewController"];

--
Gitblit v1.8.0