├── .gitignore ├── LICENSE ├── LookinDemo ├── LookinCustomInfoDemo │ ├── LookinCustomInfoDemo.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── LookinCustomInfoDemo.xcscheme │ ├── LookinCustomInfoDemo.xcworkspace │ │ └── contents.xcworkspacedata │ ├── LookinCustomInfoDemo │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Demo │ │ │ ├── ObjectiveC │ │ │ │ ├── CatView.h │ │ │ │ ├── CatView.m │ │ │ │ ├── DogLayer.h │ │ │ │ ├── DogLayer.m │ │ │ │ ├── SomeViewModel.h │ │ │ │ ├── SomeViewModel.m │ │ │ │ ├── UIView+Custom.h │ │ │ │ └── UIView+Custom.m │ │ │ └── Swift │ │ │ │ ├── BirdView.swift │ │ │ │ ├── CALayer+Custom.swift │ │ │ │ ├── GoodViewModel.swift │ │ │ │ └── HorseLayer.swift │ │ ├── Info.plist │ │ ├── LookinCustomInfoDemo-Bridging-Header.h │ │ ├── SceneDelegate.swift │ │ └── ViewController.swift │ ├── Podfile │ └── Podfile.lock ├── OC_Pod │ ├── LookinDemoOC.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── LookinDemoOC.xcscheme │ ├── LookinDemoOC.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── LookinDemoOC │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── Logo_128.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── Logo_128.png │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── CatView.h │ │ ├── CatView.m │ │ ├── Info.plist │ │ ├── SceneDelegate.h │ │ ├── SceneDelegate.m │ │ ├── ViewController.h │ │ ├── ViewController.m │ │ └── main.m │ ├── Podfile │ └── Podfile.lock ├── Swift_SPM_Debug │ ├── LookinDemoSwift.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── LookinDemoSwift.xcscheme │ └── LookinDemoSwift │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── SceneDelegate.swift │ │ └── ViewController.swift ├── Swift_SPM_Release │ ├── LookinDemoSwift.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── LookinDemoSwift.xcscheme │ └── LookinDemoSwift │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── SceneDelegate.swift │ │ └── ViewController.swift └── TestVisionOS │ ├── Podfile │ ├── Podfile.lock │ ├── TestVisionOS.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ ├── TestVisionOS.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── TestVisionOS │ ├── Assets.xcassets │ ├── AppIcon.solidimagestack │ │ ├── Back.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ └── Middle.solidimagestacklayer │ │ │ ├── Content.imageset │ │ │ └── Contents.json │ │ │ └── Contents.json │ └── Contents.json │ ├── ContentView.swift │ ├── Info.plist │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ └── TestVisionOSApp.swift ├── LookinServer.podspec ├── LookinShared.podspec ├── Package.swift ├── README.md └── Src ├── Base ├── LookinIvarTrace.h └── LookinIvarTrace.m ├── Main ├── Server │ ├── Category │ │ ├── CALayer+LookinServer.h │ │ ├── CALayer+LookinServer.m │ │ ├── NSObject+LookinServer.h │ │ ├── NSObject+LookinServer.m │ │ ├── UIBlurEffect+LookinServer.h │ │ ├── UIBlurEffect+LookinServer.m │ │ ├── UIColor+LookinServer.h │ │ ├── UIColor+LookinServer.m │ │ ├── UIImage+LookinServer.h │ │ ├── UIImage+LookinServer.m │ │ ├── UIImageView+LookinServer.h │ │ ├── UIImageView+LookinServer.m │ │ ├── UILabel+LookinServer.h │ │ ├── UILabel+LookinServer.m │ │ ├── UITableView+LookinServer.h │ │ ├── UITableView+LookinServer.m │ │ ├── UITextField+LookinServer.h │ │ ├── UITextField+LookinServer.m │ │ ├── UITextView+LookinServer.h │ │ ├── UITextView+LookinServer.m │ │ ├── UIView+LookinServer.h │ │ ├── UIView+LookinServer.m │ │ ├── UIViewController+LookinServer.h │ │ ├── UIViewController+LookinServer.m │ │ ├── UIVisualEffectView+LookinServer.h │ │ └── UIVisualEffectView+LookinServer.m │ ├── Connection │ │ ├── LKS_ConnectionManager.h │ │ ├── LKS_ConnectionManager.m │ │ ├── LKS_RequestHandler.h │ │ ├── LKS_RequestHandler.m │ │ └── RequestHandler │ │ │ ├── LKS_AttrModificationPatchHandler.h │ │ │ ├── LKS_AttrModificationPatchHandler.m │ │ │ ├── LKS_CustomAttrModificationHandler.h │ │ │ ├── LKS_CustomAttrModificationHandler.m │ │ │ ├── LKS_HierarchyDetailsHandler.h │ │ │ ├── LKS_HierarchyDetailsHandler.m │ │ │ ├── LKS_InbuiltAttrModificationHandler.h │ │ │ └── LKS_InbuiltAttrModificationHandler.m │ ├── LookinServer.h │ └── Others │ │ ├── LKSConfigManager.h │ │ ├── LKSConfigManager.m │ │ ├── LKS_AttrGroupsMaker.h │ │ ├── LKS_AttrGroupsMaker.m │ │ ├── LKS_CustomAttrGroupsMaker.h │ │ ├── LKS_CustomAttrGroupsMaker.m │ │ ├── LKS_CustomAttrSetterManager.h │ │ ├── LKS_CustomAttrSetterManager.m │ │ ├── LKS_CustomDisplayItemsMaker.h │ │ ├── LKS_CustomDisplayItemsMaker.m │ │ ├── LKS_EventHandlerMaker.h │ │ ├── LKS_EventHandlerMaker.m │ │ ├── LKS_ExportManager.h │ │ ├── LKS_ExportManager.m │ │ ├── LKS_GestureTargetActionsSearcher.h │ │ ├── LKS_GestureTargetActionsSearcher.m │ │ ├── LKS_Helper.h │ │ ├── LKS_Helper.m │ │ ├── LKS_HierarchyDisplayItemsMaker.h │ │ ├── LKS_HierarchyDisplayItemsMaker.m │ │ ├── LKS_MultiplatformAdapter.h │ │ ├── LKS_MultiplatformAdapter.m │ │ ├── LKS_ObjectRegistry.h │ │ ├── LKS_ObjectRegistry.m │ │ ├── LKS_TraceManager.h │ │ ├── LKS_TraceManager.m │ │ └── LookinServerDefines.h └── Shared │ ├── Category │ ├── CALayer+Lookin.h │ ├── CALayer+Lookin.m │ ├── Color+Lookin.h │ ├── Color+Lookin.m │ ├── Image+Lookin.h │ ├── Image+Lookin.m │ ├── NSArray+Lookin.h │ ├── NSArray+Lookin.m │ ├── NSObject+Lookin.h │ ├── NSObject+Lookin.m │ ├── NSSet+Lookin.h │ ├── NSSet+Lookin.m │ ├── NSString+Lookin.h │ └── NSString+Lookin.m │ ├── LookinAppInfo.h │ ├── LookinAppInfo.m │ ├── LookinAttrIdentifiers.h │ ├── LookinAttrIdentifiers.m │ ├── LookinAttrType.h │ ├── LookinAttribute.h │ ├── LookinAttribute.m │ ├── LookinAttributeModification.h │ ├── LookinAttributeModification.m │ ├── LookinAttributesGroup.h │ ├── LookinAttributesGroup.m │ ├── LookinAttributesSection.h │ ├── LookinAttributesSection.m │ ├── LookinAutoLayoutConstraint.h │ ├── LookinAutoLayoutConstraint.m │ ├── LookinCodingValueType.h │ ├── LookinConnectionAttachment.h │ ├── LookinConnectionAttachment.m │ ├── LookinConnectionResponseAttachment.h │ ├── LookinConnectionResponseAttachment.m │ ├── LookinCustomAttrModification.h │ ├── LookinCustomAttrModification.m │ ├── LookinCustomDisplayItemInfo.h │ ├── LookinCustomDisplayItemInfo.m │ ├── LookinDashboardBlueprint.h │ ├── LookinDashboardBlueprint.m │ ├── LookinDefines.h │ ├── LookinDisplayItem.h │ ├── LookinDisplayItem.m │ ├── LookinDisplayItemDetail.h │ ├── LookinDisplayItemDetail.m │ ├── LookinEventHandler.h │ ├── LookinEventHandler.m │ ├── LookinHierarchyFile.h │ ├── LookinHierarchyFile.m │ ├── LookinHierarchyInfo.h │ ├── LookinHierarchyInfo.m │ ├── LookinObject.h │ ├── LookinObject.m │ ├── LookinStaticAsyncUpdateTask.h │ ├── LookinStaticAsyncUpdateTask.m │ ├── LookinTuple.h │ ├── LookinTuple.m │ ├── LookinWeakContainer.h │ ├── LookinWeakContainer.m │ └── Peertalk │ ├── Lookin_PTChannel.h │ ├── Lookin_PTChannel.m │ ├── Lookin_PTPrivate.h │ ├── Lookin_PTProtocol.h │ ├── Lookin_PTProtocol.m │ ├── Lookin_PTUSBHub.h │ ├── Lookin_PTUSBHub.m │ └── Peertalk.h └── Swift └── LKS_SwiftTraceManager.swift /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2023] [LI KAI] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo.xcodeproj/xcshareddata/xcschemes/LookinCustomInfoDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 42 | 44 | 50 | 51 | 52 | 53 | 59 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/CatView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CatView.h 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2023/10/16. 6 | // 7 | 8 | #import 9 | 10 | @interface CatView : UIView 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/DogLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // DogLayer.h 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface DogLayer : CALayer 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/SomeViewModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SomeViewModel.h 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/11. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface SomeViewModel : NSObject 13 | 14 | @property(nonatomic, strong) UIView *viewModelTargetView; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/SomeViewModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SomeViewModel.m 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/11. 6 | // 7 | 8 | #import "SomeViewModel.h" 9 | 10 | @implementation SomeViewModel 11 | 12 | - (instancetype)init 13 | { 14 | self = [super init]; 15 | if (self) { 16 | [[NSNotificationCenter defaultCenter] postNotificationName:@"Lookin_RelationSearch" object:self]; 17 | } 18 | return self; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/UIView+Custom.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Custom.h 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface UIView (Custom) 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/ObjectiveC/UIView+Custom.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Custom.m 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | #import "UIView+Custom.h" 9 | 10 | @implementation UIView (Custom) 11 | 12 | /// 实现该方法以在 Lookin 中展示自定义属性 13 | /// 请留意该方法是否已经被父类、子类、分类实现了,如果是,为了避免冲突,你可以把该方法更名为 lookin_customDebugInfos_0(末尾的数字 0 可以被替换为 0 ~ 5 中的任意数字) 14 | /// 每次 Lookin 刷新时都会调用该方法,因此若该方法耗时较长,则会拖慢刷新速度 15 | /// 16 | /// Implement this method to display custom properties in Lookin. 17 | /// Please note if this method has already been implemented by the superclass, subclass, or category. If so, to avoid conflicts, you can rename this method to lookin_customDebugInfos_0 (the trailing number 0 can be replaced with any number from 0 to 5). 18 | /// This method is called every time Lookin refreshes, so if this method takes a long time to execute, it will slow down the refresh speed. 19 | /// 20 | /// https://bytedance.feishu.cn/docx/TRridRXeUoErMTxs94bcnGchnlb 21 | - (NSDictionary *)lookin_customDebugInfos_0 { 22 | NSDictionary *ret = @{ 23 | @"properties": [self category_makeCustomProperties], 24 | }; 25 | return ret; 26 | } 27 | 28 | - (NSArray *)category_makeCustomProperties { 29 | NSMutableArray *properties = [NSMutableArray array]; 30 | 31 | [properties addObject:@{ 32 | @"section": @"Appearance", 33 | @"title": @"Brightness", 34 | @"value": @8.8, 35 | @"valueType": @"number" 36 | }]; 37 | 38 | return [properties copy];; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/Swift/CALayer+Custom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+Custom.swift 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | import UIKit 9 | 10 | extension CALayer { 11 | /// 实现该方法以在 Lookin 中展示自定义属性 12 | /// 请留意该方法是否已经被父类、子类、分类实现了,如果是,为了避免冲突,你可以把该方法更名为 lookin_customDebugInfos_0(末尾的数字 0 可以被替换为 0 ~ 5 中的任意数字) 13 | /// 每次 Lookin 刷新时都会调用该方法,因此若该方法耗时较长,则会拖慢刷新速度 14 | /// 15 | /// Implement this method to display custom properties in Lookin. 16 | /// Please note if this method has already been implemented by the superclass, subclass, or category. If so, to avoid conflicts, you can rename this method to lookin_customDebugInfos_0 (the trailing number 0 can be replaced with any number from 0 to 5). 17 | /// This method is called every time Lookin refreshes, so if this method takes a long time to execute, it will slow down the refresh speed. 18 | /// 19 | /// https://bytedance.feishu.cn/docx/TRridRXeUoErMTxs94bcnGchnlb 20 | @objc func lookin_customDebugInfos_1() -> [String:Any]? { 21 | let ret: [String:Any] = [ 22 | "properties": self.cusotm_makeCustomProperties() 23 | ] 24 | return ret 25 | } 26 | 27 | private func cusotm_makeCustomProperties() -> [Any] { 28 | let stringProperty: [String:Any] = [ 29 | "section": "Life Style", 30 | "title": "Hobby", 31 | "value": "Bike", 32 | "valueType": "string" 33 | ] 34 | 35 | return [stringProperty] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Demo/Swift/GoodViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoodViewModel.swift 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | class GoodViewModel { 11 | var viewModelTargetView: UIView? 12 | 13 | init() { 14 | NotificationCenter.default.post(name: .init("Lookin_RelationSearch"), object: self) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/LookinCustomInfoDemo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "CatView.h" 6 | #import "DogLayer.h" 7 | #import "SomeViewModel.h" 8 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/LookinCustomInfoDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // LookinCustomInfoDemo 4 | // 5 | // Created by likai.123 on 2023/11/2. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'LookinCustomInfoDemo' do 4 | pod 'LookinServer', :path=>'../../', :subspecs => ['Swift'], :configurations => ['Debug'] 5 | end 6 | -------------------------------------------------------------------------------- /LookinDemo/LookinCustomInfoDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - LookinServer/Core (1.2.7) 3 | - LookinServer/Swift (1.2.7): 4 | - LookinServer/Core 5 | 6 | DEPENDENCIES: 7 | - LookinServer/Swift (from `../../`) 8 | 9 | EXTERNAL SOURCES: 10 | LookinServer: 11 | :path: "../../" 12 | 13 | SPEC CHECKSUMS: 14 | LookinServer: fccc36fcab6ea15ae70692872877add9ce005f56 15 | 16 | PODFILE CHECKSUM: 46caada19d34f471f9e44165d96af39e799fd091 17 | 18 | COCOAPODS: 1.13.0 19 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC.xcodeproj/xcshareddata/xcschemes/LookinDemoOC.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | @interface AppDelegate () 11 | 12 | @end 13 | 14 | @implementation AppDelegate 15 | 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 18 | // Override point for customization after application launch. 19 | return YES; 20 | } 21 | 22 | 23 | #pragma mark - UISceneSession lifecycle 24 | 25 | 26 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { 27 | // Called when a new scene session is being created. 28 | // Use this method to select a configuration to create the new scene with. 29 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; 30 | } 31 | 32 | 33 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { 34 | // Called when the user discards a scene session. 35 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 36 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 37 | } 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/Logo_128.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "Logo_128.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/Logo_128.imageset/Logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QMUI/LookinServer/ae396132ce6494477457cf450116dc760518d8ad/LookinDemo/OC_Pod/LookinDemoOC/Assets.xcassets/Logo_128.imageset/Logo_128.png -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/CatView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CatView.h 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2023/10/16. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface CatView : UIView 13 | 14 | - (NSDictionary *)lookin_customDebugInfos; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/SceneDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.h 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import 9 | 10 | @interface SceneDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow * window; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/SceneDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.m 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import "SceneDelegate.h" 9 | 10 | @interface SceneDelegate () 11 | 12 | @end 13 | 14 | @implementation SceneDelegate 15 | 16 | 17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 21 | } 22 | 23 | 24 | - (void)sceneDidDisconnect:(UIScene *)scene { 25 | // Called as the scene is being released by the system. 26 | // This occurs shortly after the scene enters the background, or when its session is discarded. 27 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 29 | } 30 | 31 | 32 | - (void)sceneDidBecomeActive:(UIScene *)scene { 33 | // Called when the scene has moved from an inactive state to an active state. 34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 35 | } 36 | 37 | 38 | - (void)sceneWillResignActive:(UIScene *)scene { 39 | // Called when the scene will move from an active state to an inactive state. 40 | // This may occur due to temporary interruptions (ex. an incoming phone call). 41 | } 42 | 43 | 44 | - (void)sceneWillEnterForeground:(UIScene *)scene { 45 | // Called as the scene transitions from the background to the foreground. 46 | // Use this method to undo the changes made on entering the background. 47 | } 48 | 49 | 50 | - (void)sceneDidEnterBackground:(UIScene *)scene { 51 | // Called as the scene transitions from the foreground to the background. 52 | // Use this method to save data, release shared resources, and store enough scene-specific state information 53 | // to restore the scene back to its current state. 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import 9 | 10 | @interface ViewController : UIViewController 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import "ViewController.h" 9 | #import "CatView.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // 创建 UIStackView 20 | UIStackView *stackView = [[UIStackView alloc] init]; 21 | stackView.axis = UILayoutConstraintAxisVertical; // 设置布局方向为垂直 22 | stackView.alignment = UIStackViewAlignmentFill; // 设置对齐方式为居中对齐 23 | stackView.distribution = UIStackViewDistributionFillEqually; // 设置子视图的分布方式为均匀分布 24 | stackView.spacing = 10.0; // 设置子视图之间的间距为10 25 | 26 | // 创建子视图 27 | UIView *view1 = [[UIView alloc] init]; 28 | view1.backgroundColor = [UIColor redColor]; 29 | UIView *view2 = [[UIView alloc] init]; 30 | view2.backgroundColor = [UIColor greenColor]; 31 | UIView *view3 = [[UIView alloc] init]; 32 | view3.backgroundColor = [UIColor blueColor]; 33 | 34 | // 将子视图添加到 UIStackView 中 35 | [stackView addArrangedSubview:view1]; 36 | [stackView addArrangedSubview:view2]; 37 | [stackView addArrangedSubview:view3]; 38 | 39 | // 将 UIStackView 添加到父视图中 40 | [self.view addSubview:stackView]; 41 | 42 | stackView.frame = self.view.bounds; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/LookinDemoOC/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LookinDemoOC 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) { 12 | NSString * appDelegateClassName; 13 | @autoreleasepool { 14 | // Setup code that might create autoreleased objects goes here. 15 | appDelegateClassName = NSStringFromClass([AppDelegate class]); 16 | } 17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 18 | } 19 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'LookinDemoOC' do 4 | pod 'LookinServer', :path=>'../../' 5 | end 6 | -------------------------------------------------------------------------------- /LookinDemo/OC_Pod/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - LookinServer (1.2.6): 3 | - LookinServer/Core (= 1.2.6) 4 | - LookinServer/Core (1.2.6) 5 | 6 | DEPENDENCIES: 7 | - LookinServer (from `../../`) 8 | 9 | EXTERNAL SOURCES: 10 | LookinServer: 11 | :path: "../../" 12 | 13 | SPEC CHECKSUMS: 14 | LookinServer: de929b55f8fa2e241c18c39af3f900eaa9166389 15 | 16 | PODFILE CHECKSUM: c1b5f203c9e81bcbf3888ba95a03c31e2435a4f7 17 | 18 | COCOAPODS: 1.13.0 19 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "lookinserver", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/QMUI/LookinServer", 7 | "state" : { 8 | "branch" : "develop", 9 | "revision" : "6637da86966513ceaf584e48835518d36f5aa977" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift.xcodeproj/xcshareddata/xcschemes/LookinDemoSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Debug/LookinDemoSwift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | extension NSObject { 11 | @objc func lookin_shouldCaptureImageOfView(_ view: UIView) -> Bool { 12 | if view.tag == 1234 { 13 | return true 14 | } else { 15 | return true 16 | } 17 | } 18 | 19 | @objc func lookin_collapsedClassList() -> [String] { 20 | return ["UIDropShadowView"] 21 | } 22 | 23 | @objc func lookin_colorAlias() -> [String:UIColor] { 24 | return ["MyWhite": UIColor.init(red: 1, green: 1, blue: 1, alpha: 1)] 25 | } 26 | } 27 | 28 | class MyView: UIView { 29 | @objc func lookin_shouldCaptureImage() -> Bool { 30 | return false 31 | } 32 | } 33 | 34 | class ViewController: UIViewController { 35 | private let myButton = MyView() 36 | 37 | private let textView = UITextView() 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | // Do any additional setup after loading the view. 42 | self.view.layer.borderColor = UIColor.red.cgColor 43 | 44 | textView.frame = CGRect(x: 20, y: 100, width: 200, height: 200) 45 | view.addSubview(textView) 46 | 47 | myButton.tag = 1234 48 | myButton.frame = CGRect(x: 20, y: 20, width: 50, height: 50) 49 | view.addSubview(myButton) 50 | } 51 | 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "lookinserver", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/QMUI/LookinServer", 7 | "state" : { 8 | "branch" : "develop", 9 | "revision" : "58067cf9cd30662f7082681d8f5083524a4262b1" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift.xcodeproj/xcshareddata/xcschemes/LookinDemoSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /LookinDemo/Swift_SPM_Release/LookinDemoSwift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // LookinDemoSwift 4 | // 5 | // Created by likai.123 on 2022/10/10. 6 | // 7 | 8 | import UIKit 9 | 10 | extension NSObject { 11 | @objc func lookin_shouldCaptureImageOfView(_ view: UIView) -> Bool { 12 | if view.tag == 1234 { 13 | return true 14 | } else { 15 | return true 16 | } 17 | } 18 | 19 | @objc func lookin_collapsedClassList() -> [String] { 20 | return ["UIDropShadowView"] 21 | } 22 | 23 | @objc func lookin_colorAlias() -> [String:UIColor] { 24 | return ["MyWhite": UIColor.init(red: 1, green: 1, blue: 1, alpha: 1)] 25 | } 26 | } 27 | 28 | class MyView: UIView { 29 | @objc func lookin_shouldCaptureImage() -> Bool { 30 | return false 31 | } 32 | } 33 | 34 | class ViewController: UIViewController { 35 | private let myButton = MyView() 36 | 37 | private let textView = UITextView() 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | // Do any additional setup after loading the view. 42 | self.view.layer.borderColor = UIColor.red.cgColor 43 | 44 | textView.frame = CGRect(x: 20, y: 100, width: 200, height: 200) 45 | view.addSubview(textView) 46 | 47 | myButton.tag = 1234 48 | myButton.frame = CGRect(x: 20, y: 20, width: 50, height: 50) 49 | view.addSubview(myButton) 50 | } 51 | 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'TestVisionOS' do 4 | pod 'LookinServer', :path=>'../../', :subspecs => ['Swift'], :configurations => ['Debug'] 5 | end 6 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - LookinServer/Core (1.2.7) 3 | - LookinServer/Swift (1.2.7): 4 | - LookinServer/Core 5 | 6 | DEPENDENCIES: 7 | - LookinServer/Swift (from `../../`) 8 | 9 | EXTERNAL SOURCES: 10 | LookinServer: 11 | :path: "../../" 12 | 13 | SPEC CHECKSUMS: 14 | LookinServer: fccc36fcab6ea15ae70692872877add9ce005f56 15 | 16 | PODFILE CHECKSUM: 1dcff374267c2c2621d26b1dcf8fa7af55b2055b 17 | 18 | COCOAPODS: 1.13.0 19 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "vision", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.solidimagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.solidimagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.solidimagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "vision", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "vision", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // TestVisionOS 4 | // 5 | // Created by likai.123 on 2024/4/6. 6 | // 7 | 8 | import SwiftUI 9 | import RealityKit 10 | import RealityKitContent 11 | 12 | struct ContentView: View { 13 | var body: some View { 14 | VStack { 15 | Model3D(named: "Scene", bundle: realityKitContentBundle) 16 | .padding(.bottom, 50) 17 | 18 | Text("Hello, world!") 19 | } 20 | .padding() 21 | } 22 | } 23 | 24 | #Preview(windowStyle: .automatic) { 25 | ContentView() 26 | } 27 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationPreferredDefaultSceneSessionRole 8 | UIWindowSceneSessionRoleApplication 9 | UIApplicationSupportsMultipleScenes 10 | 11 | UISceneConfigurations 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LookinDemo/TestVisionOS/TestVisionOS/TestVisionOSApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestVisionOSApp.swift 3 | // TestVisionOS 4 | // 5 | // Created by likai.123 on 2024/4/6. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct TestVisionOSApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LookinServer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = "LookinServer" 3 | spec.version = "1.2.8" 4 | spec.summary = "The iOS framework of Lookin." 5 | spec.description = "Embed this framework into your iOS project to enable Lookin mac app." 6 | spec.homepage = "https://lookin.work" 7 | spec.license = "GPL-3.0" 8 | spec.author = { "Li Kai" => "lookin@lookin.work" } 9 | spec.ios.deployment_target = "9.0" 10 | spec.tvos.deployment_target = '9.0' 11 | spec.visionos.deployment_target = "1.0" 12 | spec.default_subspecs = 'Core' 13 | spec.source = { :git => "https://github.com/QMUI/LookinServer.git", :tag => "1.2.8"} 14 | spec.framework = "UIKit" 15 | spec.requires_arc = true 16 | 17 | spec.subspec 'Core' do |ss| 18 | ss.source_files = ['Src/Main/**/*', 'Src/Base/**/*'] 19 | ss.pod_target_xcconfig = { 20 | 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER=1', 21 | 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER' 22 | } 23 | end 24 | 25 | spec.subspec 'Swift' do |ss| 26 | ss.dependency 'LookinServer/Core' 27 | ss.source_files = 'Src/Swift/**/*' 28 | ss.pod_target_xcconfig = { 29 | 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED=1', 30 | 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED' 31 | } 32 | end 33 | 34 | spec.subspec 'NoHook' do |ss| 35 | ss.dependency 'LookinServer/Core' 36 | ss.pod_target_xcconfig = { 37 | 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_DISABLE_HOOK=1', 38 | } 39 | end 40 | 41 | # CocoaPods 不支持多个 subspecs 和 configurations 并列 42 | # "pod 'LookinServer', :subspecs => ['Swift', 'NoHook'], :configurations => ['Debug']" is not supported by CocoaPods 43 | # https://github.com/QMUI/LookinServer/issues/134 44 | spec.subspec 'SwiftAndNoHook' do |ss| 45 | ss.dependency 'LookinServer/Core' 46 | ss.source_files = 'Src/Swift/**/*' 47 | ss.pod_target_xcconfig = { 48 | 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED=1 LOOKIN_SERVER_DISABLE_HOOK=1', 49 | 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED' 50 | } 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /LookinShared.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = "LookinShared" 3 | spec.version = "1.2.8" 4 | spec.summary = "The shared files between client and server side of Lookin." 5 | spec.description = "Embed this framework into your iOS project to enable Lookin mac app." 6 | spec.homepage = "https://lookin.work" 7 | spec.license = "GPL-3.0" 8 | spec.author = { "Li Kai" => "lookin@lookin.work" } 9 | spec.ios.deployment_target = "9.0" 10 | spec.tvos.deployment_target = '9.0' 11 | spec.macos.deployment_target = "10.14" 12 | spec.visionos.deployment_target = "1.0" 13 | spec.source = { :git => "https://github.com/QMUI/LookinServer.git", :tag => "1.2.8"} 14 | #spec.framework = "UIKit" 15 | spec.requires_arc = true 16 | spec.source_files = [ 17 | 'Src/Main/Shared/**/*', 18 | 'Src/Base/**/*' 19 | ] 20 | spec.pod_target_xcconfig = { 21 | 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER=1' 22 | } 23 | end 24 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "LookinServer", 8 | platforms: [ 9 | .iOS(.v9),.tvOS(.v9) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "LookinServer", 15 | targets: ["LookinServer"]), 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "LookinServer", 26 | dependencies: [.target(name: "LookinServerSwift")], 27 | path: "Src/Main", 28 | publicHeadersPath: "", 29 | cSettings: [ 30 | .headerSearchPath("**"), 31 | .headerSearchPath("Server"), 32 | .headerSearchPath("Server/Category"), 33 | .headerSearchPath("Server/Connection"), 34 | .headerSearchPath("Server/Connection/RequestHandler"), 35 | .headerSearchPath("Server/Inspect"), 36 | .headerSearchPath("Server/Others"), 37 | .headerSearchPath("Server/Perspective"), 38 | .headerSearchPath("Shared"), 39 | .headerSearchPath("Shared/Category"), 40 | .headerSearchPath("Shared/Message"), 41 | .headerSearchPath("Shared/Peertalk"), 42 | ], 43 | cxxSettings: [ 44 | .define("SHOULD_COMPILE_LOOKIN_SERVER", to: "1", .when(configuration: .debug)), 45 | .define("SPM_LOOKIN_SERVER_ENABLED", to: "1", .when(configuration: .debug)) 46 | ] 47 | ), 48 | .target( 49 | name: "LookinServerSwift", 50 | dependencies: [.target(name: "LookinServerBase")], 51 | path: "Src/Swift", 52 | cxxSettings: [ 53 | .define("SHOULD_COMPILE_LOOKIN_SERVER", to: "1", .when(configuration: .debug)), 54 | .define("SPM_LOOKIN_SERVER_ENABLED", to: "1", .when(configuration: .debug)) 55 | ], 56 | swiftSettings: [ 57 | .define("SHOULD_COMPILE_LOOKIN_SERVER", .when(configuration: .debug)), 58 | .define("SPM_LOOKIN_SERVER_ENABLED", .when(configuration: .debug)) 59 | ] 60 | ), 61 | .target( 62 | name: "LookinServerBase", 63 | dependencies: [], 64 | path: "Src/Base", 65 | publicHeadersPath: "", 66 | cxxSettings: [ 67 | .define("SHOULD_COMPILE_LOOKIN_SERVER", to: "1", .when(configuration: .debug)) 68 | ] 69 | ) 70 | ] 71 | ) 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Preview](https://cdn.lookin.work/public/style/images/independent/homepage/preview_en_1x.jpg "Preview") 2 | 3 | # Introduction 4 | You can inspect and modify views in iOS app via Lookin, just like UI Inspector in Xcode, or another app called Reveal. 5 | 6 | Official Website:https://lookin.work/ 7 | 8 | # Integration Guide 9 | To use Lookin macOS app, you need to integrate LookinServer (iOS Framework of Lookin) into your iOS project. 10 | 11 | > **Warning** 12 | > 1. Never integrate LookinServer in Release building configuration. 13 | > 2. Do not use versions earlier than 1.0.6, as it contains a critical bug that could lead to online incidents in your project: https://qxh1ndiez2w.feishu.cn/wiki/Z9SpwT7zWiqvYvkBe7Lc6Disnab 14 | 15 | ## via CocoaPods: 16 | ### Swift Project 17 | `pod 'LookinServer', :subspecs => ['Swift'], :configurations => ['Debug']` 18 | ### Objective-C Project 19 | `pod 'LookinServer', :configurations => ['Debug']` 20 | ## via Swift Package Manager: 21 | `https://github.com/QMUI/LookinServer/` 22 | 23 | # Repository 24 | LookinServer: https://github.com/QMUI/LookinServer 25 | 26 | macOS app: https://github.com/hughkli/Lookin/ 27 | 28 | # Tips 29 | - How to display custom information in Lookin: https://bytedance.larkoffice.com/docx/TRridRXeUoErMTxs94bcnGchnlb 30 | - How to display more member variables in Lookin: https://bytedance.larkoffice.com/docx/CKRndHqdeoub11xSqUZcMlFhnWe 31 | - How to turn on Swift optimization for Lookin: https://bytedance.larkoffice.com/docx/GFRLdzpeKoakeyxvwgCcZ5XdnTb 32 | - Documentation Collection: https://bytedance.larkoffice.com/docx/Yvv1d57XQoe5l0xZ0ZRc0ILfnWb 33 | 34 | # Acknowledgements 35 | https://qxh1ndiez2w.feishu.cn/docx/YIFjdE4gIolp3hxn1tGckiBxnWf 36 | 37 | --- 38 | # 简介 39 | Lookin 可以查看与修改 iOS App 里的 UI 对象,类似于 Xcode 自带的 UI Inspector 工具,或另一款叫做 Reveal 的软件。 40 | 41 | 官网:https://lookin.work/ 42 | 43 | # 安装 LookinServer Framework 44 | 如果这是你的 iOS 项目第一次使用 Lookin,则需要先把 LookinServer 这款 iOS Framework 集成到你的 iOS 项目中。 45 | 46 | > **Warning** 47 | > 48 | > 1. 不要在 AppStore 模式下集成 LookinServer。 49 | > 2. 不要使用早于 1.0.6 的版本,因为它包含一个严重 Bug,可能导致线上事故: https://qxh1ndiez2w.feishu.cn/wiki/Z9SpwT7zWiqvYvkBe7Lc6Disnab 50 | ## 通过 CocoaPods: 51 | 52 | ### Swift 项目 53 | `pod 'LookinServer', :subspecs => ['Swift'], :configurations => ['Debug']` 54 | ### Objective-C 项目 55 | `pod 'LookinServer', :configurations => ['Debug']` 56 | 57 | ## 通过 Swift Package Manager: 58 | `https://github.com/QMUI/LookinServer/` 59 | 60 | # 源代码仓库 61 | 62 | iOS 端 LookinServer:https://github.com/QMUI/LookinServer 63 | 64 | macOS 端软件:https://github.com/hughkli/Lookin/ 65 | 66 | # 技巧 67 | - 如何在 Lookin 中展示自定义信息: https://bytedance.larkoffice.com/docx/TRridRXeUoErMTxs94bcnGchnlb 68 | - 如何在 Lookin 中展示更多成员变量: https://bytedance.larkoffice.com/docx/CKRndHqdeoub11xSqUZcMlFhnWe 69 | - 如何为 Lookin 开启 Swift 优化: https://bytedance.larkoffice.com/docx/GFRLdzpeKoakeyxvwgCcZ5XdnTb 70 | - 文档汇总:https://bytedance.larkoffice.com/docx/Yvv1d57XQoe5l0xZ0ZRc0ILfnWb 71 | 72 | # 鸣谢 73 | https://qxh1ndiez2w.feishu.cn/docx/YIFjdE4gIolp3hxn1tGckiBxnWf 74 | -------------------------------------------------------------------------------- /Src/Base/LookinIvarTrace.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinIvarTrace.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/4/30. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | extern NSString *const LookinIvarTraceRelationValue_Self; 14 | 15 | /// 如果 hostClassName 和 ivarName 均 equal,则认为两个 LookinIvarTrace 对象彼此 equal 16 | /// 比如 A 是 B 的 superview,且 A 的 "_stageView" 指向 B,则 B 会有一个 LookinIvarTrace:hostType 为 “superview”,hostClassName 为 A 的 class,ivarName 为 “_stageView” 17 | @interface LookinIvarTrace : NSObject 18 | 19 | /// 该值可能是 "superview"、"superlayer"、“self” 或 nil 20 | @property(nonatomic, copy) NSString *relation; 21 | 22 | @property(nonatomic, copy) NSString *hostClassName; 23 | 24 | @property(nonatomic, copy) NSString *ivarName; 25 | 26 | #pragma mark - No Coding 27 | 28 | #if TARGET_OS_IPHONE 29 | @property(nonatomic, weak) id hostObject; 30 | #endif 31 | 32 | @end 33 | 34 | @interface NSObject (LookinServerTrace) 35 | 36 | @property(nonatomic, copy) NSArray *lks_ivarTraces; 37 | 38 | @end 39 | 40 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 41 | -------------------------------------------------------------------------------- /Src/Base/LookinIvarTrace.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinIvarTrace.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/4/30. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinIvarTrace.h" 12 | 13 | NSString *const LookinIvarTraceRelationValue_Self = @"self"; 14 | 15 | @implementation LookinIvarTrace 16 | 17 | #pragma mark - Equal 18 | 19 | - (NSUInteger)hash { 20 | return self.hostClassName.hash ^ self.ivarName.hash; 21 | } 22 | 23 | - (BOOL)isEqual:(id)object { 24 | if (self == object) { 25 | return YES; 26 | } 27 | if (![object isKindOfClass:[LookinIvarTrace class]]) { 28 | return NO; 29 | } 30 | LookinIvarTrace *comparedObj = object; 31 | if ([self.hostClassName isEqualToString:comparedObj.hostClassName] && [self.ivarName isEqualToString:comparedObj.ivarName]) { 32 | return YES; 33 | } 34 | return NO; 35 | } 36 | 37 | #pragma mark - 38 | 39 | - (id)copyWithZone:(NSZone *)zone { 40 | LookinIvarTrace *newTrace = [[LookinIvarTrace allocWithZone:zone] init]; 41 | newTrace.relation = self.relation; 42 | newTrace.hostClassName = self.hostClassName; 43 | newTrace.ivarName = self.ivarName; 44 | return newTrace; 45 | } 46 | 47 | #pragma mark - 48 | 49 | - (void)encodeWithCoder:(NSCoder *)aCoder { 50 | [aCoder encodeObject:self.relation forKey:@"relation"]; 51 | [aCoder encodeObject:self.hostClassName forKey:@"hostClassName"]; 52 | [aCoder encodeObject:self.ivarName forKey:@"ivarName"]; 53 | } 54 | 55 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 56 | if (self = [super init]) { 57 | self.relation = [aDecoder decodeObjectForKey:@"relation"]; 58 | self.hostClassName = [aDecoder decodeObjectForKey:@"hostClassName"]; 59 | self.ivarName = [aDecoder decodeObjectForKey:@"ivarName"]; 60 | } 61 | return self; 62 | } 63 | 64 | + (BOOL)supportsSecureCoding { 65 | return YES; 66 | } 67 | 68 | @end 69 | 70 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 71 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/CALayer+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIView+LookinMobile.h 5 | // WeRead 6 | // 7 | // Created by Li Kai on 2018/11/30. 8 | // Copyright © 2018 tencent. All rights reserved. 9 | // 10 | 11 | #import "LookinDefines.h" 12 | #import "TargetConditionals.h" 13 | #import 14 | 15 | @interface CALayer (LookinServer) 16 | 17 | /// 如果 myView.layer == myLayer,则 myLayer.lks_hostView 会返回 myView 18 | @property(nonatomic, readonly, weak) UIView *lks_hostView; 19 | 20 | - (UIWindow *)lks_window; 21 | 22 | - (CGRect)lks_frameInWindow:(UIWindow *)window; 23 | 24 | - (UIImage *)lks_groupScreenshotWithLowQuality:(BOOL)lowQuality; 25 | /// 当没有 sublayers 时,该方法返回 nil 26 | - (UIImage *)lks_soloScreenshotWithLowQuality:(BOOL)lowQuality; 27 | 28 | /// 获取和该对象有关的对象的 Class 层级树 29 | - (NSArray *> *)lks_relatedClassChainList; 30 | 31 | - (NSArray *)lks_selfRelation; 32 | 33 | @property(nonatomic, strong) UIColor *lks_backgroundColor; 34 | @property(nonatomic, strong) UIColor *lks_borderColor; 35 | @property(nonatomic, strong) UIColor *lks_shadowColor; 36 | @property(nonatomic, assign) CGFloat lks_shadowOffsetWidth; 37 | @property(nonatomic, assign) CGFloat lks_shadowOffsetHeight; 38 | 39 | @end 40 | 41 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 42 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/NSObject+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSObject+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/21. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | #import 13 | 14 | @class LookinIvarTrace; 15 | 16 | @interface NSObject (LookinServer) 17 | 18 | #pragma mark - oid 19 | 20 | /// 如果 oid 不存在则会创建新的 oid 21 | - (unsigned long)lks_registerOid; 22 | 23 | /// 0 表示不存在 24 | @property(nonatomic, assign) unsigned long lks_oid; 25 | 26 | + (NSObject *)lks_objectWithOid:(unsigned long)oid; 27 | 28 | #pragma mark - trace 29 | 30 | @property(nonatomic, copy) NSString *lks_specialTrace; 31 | 32 | + (void)lks_clearAllObjectsTraces; 33 | 34 | /** 35 | 获取当前对象的 Class 层级树,如 @[@"UIView", @"UIResponder", @"NSObject"]。未 demangle,有 Swift Module Name 36 | */ 37 | - (NSArray *)lks_classChainList; 38 | 39 | @end 40 | 41 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 42 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/NSObject+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSObject+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/21. 8 | // https://lookin.work 9 | // 10 | 11 | #import "NSObject+Lookin.h" 12 | #import "NSObject+LookinServer.h" 13 | #import "LookinServerDefines.h" 14 | #import "LKS_ObjectRegistry.h" 15 | #import 16 | 17 | @implementation NSObject (LookinServer) 18 | 19 | #pragma mark - oid 20 | 21 | - (unsigned long)lks_registerOid { 22 | if (!self.lks_oid) { 23 | unsigned long oid = [[LKS_ObjectRegistry sharedInstance] addObject:self]; 24 | self.lks_oid = oid; 25 | } 26 | return self.lks_oid; 27 | } 28 | 29 | - (void)setLks_oid:(unsigned long)lks_oid { 30 | [self lookin_bindObject:@(lks_oid) forKey:@"lks_oid"]; 31 | } 32 | 33 | - (unsigned long)lks_oid { 34 | NSNumber *number = [self lookin_getBindObjectForKey:@"lks_oid"]; 35 | return [number unsignedLongValue]; 36 | } 37 | 38 | + (NSObject *)lks_objectWithOid:(unsigned long)oid { 39 | return [[LKS_ObjectRegistry sharedInstance] objectWithOid:oid]; 40 | } 41 | 42 | #pragma mark - trace 43 | 44 | - (void)setLks_ivarTraces:(NSArray *)lks_ivarTraces { 45 | [self lookin_bindObject:lks_ivarTraces.copy forKey:@"lks_ivarTraces"]; 46 | 47 | if (lks_ivarTraces) { 48 | [[NSObject lks_allObjectsWithTraces] addPointer:(void *)self]; 49 | } 50 | } 51 | 52 | - (NSArray *)lks_ivarTraces { 53 | return [self lookin_getBindObjectForKey:@"lks_ivarTraces"]; 54 | } 55 | 56 | - (void)setLks_specialTrace:(NSString *)lks_specialTrace { 57 | [self lookin_bindObject:lks_specialTrace forKey:@"lks_specialTrace"]; 58 | if (lks_specialTrace) { 59 | [[NSObject lks_allObjectsWithTraces] addPointer:(void *)self]; 60 | } 61 | } 62 | - (NSString *)lks_specialTrace { 63 | return [self lookin_getBindObjectForKey:@"lks_specialTrace"]; 64 | } 65 | 66 | + (void)lks_clearAllObjectsTraces { 67 | [[[NSObject lks_allObjectsWithTraces] allObjects] enumerateObjectsUsingBlock:^(NSObject * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 68 | obj.lks_ivarTraces = nil; 69 | obj.lks_specialTrace = nil; 70 | }]; 71 | [NSObject lks_allObjectsWithTraces].count = 0; 72 | } 73 | 74 | + (NSPointerArray *)lks_allObjectsWithTraces { 75 | static dispatch_once_t onceToken; 76 | static NSPointerArray *lks_allObjectsWithTraces = nil; 77 | dispatch_once(&onceToken,^{ 78 | lks_allObjectsWithTraces = [NSPointerArray weakObjectsPointerArray]; 79 | }); 80 | return lks_allObjectsWithTraces; 81 | } 82 | 83 | - (NSArray *)lks_classChainList { 84 | NSMutableArray *classChainList = [NSMutableArray array]; 85 | Class currentClass = self.class; 86 | 87 | while (currentClass) { 88 | NSString *currentClassName = NSStringFromClass(currentClass); 89 | if (currentClassName) { 90 | [classChainList addObject:currentClassName]; 91 | } 92 | currentClass = [currentClass superclass]; 93 | } 94 | return classChainList.copy; 95 | } 96 | 97 | @end 98 | 99 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 100 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIBlurEffect+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIBlurEffect+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/10/8. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIBlurEffect (LookinServer) 14 | 15 | /// 该 number 包装的对象是 UIBlurEffectStyle,之所以用 NSNumber 是因为想把 0 和 nil 区分开,毕竟这里是在 hook 系统,稳一点好。 16 | /// 该方法的实现需要 Hook,因此若定义了 LOOKIN_SERVER_DISABLE_HOOK 宏,则属性会返回 nil 17 | @property(nonatomic, strong) NSNumber *lks_effectStyleNumber; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIBlurEffect+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIBlurEffect+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/10/8. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UIBlurEffect+LookinServer.h" 12 | #import "NSObject+Lookin.h" 13 | #import 14 | 15 | @implementation UIBlurEffect (LookinServer) 16 | 17 | #ifdef LOOKIN_SERVER_DISABLE_HOOK 18 | 19 | - (void)setLks_effectStyleNumber:(NSNumber *)lks_effectStyleNumber { 20 | } 21 | 22 | - (NSNumber *)lks_effectStyleNumber { 23 | return nil; 24 | } 25 | 26 | #else 27 | 28 | + (void)load { 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | Method oriMethod = class_getClassMethod([self class], @selector(effectWithStyle:)); 32 | Method newMethod = class_getClassMethod([self class], @selector(lks_effectWithStyle:)); 33 | method_exchangeImplementations(oriMethod, newMethod); 34 | }); 35 | } 36 | 37 | + (UIBlurEffect *)lks_effectWithStyle:(UIBlurEffectStyle)style { 38 | id effect = [self lks_effectWithStyle:style]; 39 | if ([effect respondsToSelector:@selector(setLks_effectStyleNumber:)]) { 40 | [effect setLks_effectStyleNumber:@(style)]; 41 | } 42 | return effect; 43 | } 44 | 45 | - (void)setLks_effectStyleNumber:(NSNumber *)lks_effectStyleNumber { 46 | [self lookin_bindObject:lks_effectStyleNumber forKey:@"lks_effectStyleNumber"]; 47 | } 48 | 49 | - (NSNumber *)lks_effectStyleNumber { 50 | return [self lookin_getBindObjectForKey:@"lks_effectStyleNumber"]; 51 | } 52 | 53 | #endif /* LOOKIN_SERVER_DISABLE_HOOK */ 54 | 55 | @end 56 | 57 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 58 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIColor+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIColor+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/5. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIColor (LookinServer) 14 | 15 | - (NSArray *)lks_rgbaComponents; 16 | + (instancetype)lks_colorFromRGBAComponents:(NSArray *)components; 17 | 18 | - (NSString *)lks_rgbaString; 19 | - (NSString *)lks_hexString; 20 | 21 | /// will check if the argument is a real CGColor 22 | + (UIColor *)lks_colorWithCGColor:(CGColorRef)cgColor; 23 | 24 | @end 25 | 26 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 27 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIImage+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIImage+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/5/14. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIImage (LookinServer) 14 | 15 | /// 该方法的实现需要 Hook,因此若定义了 LOOKIN_SERVER_DISABLE_HOOK 宏,则属性会返回 nil 16 | @property(nonatomic, copy) NSString *lks_imageSourceName; 17 | 18 | - (NSData *)lookin_data; 19 | 20 | @end 21 | 22 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 23 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIImageView+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIImageView+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/9/18. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIImageView (LookinServer) 14 | 15 | - (NSString *)lks_imageSourceName; 16 | - (NSNumber *)lks_imageViewOidIfHasImage; 17 | 18 | @end 19 | 20 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 21 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIImageView+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIImageView+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/9/18. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UIImageView+LookinServer.h" 12 | #import "UIImage+LookinServer.h" 13 | #import "NSObject+LookinServer.h" 14 | 15 | @implementation UIImageView (LookinServer) 16 | 17 | - (NSString *)lks_imageSourceName { 18 | return self.image.lks_imageSourceName; 19 | } 20 | 21 | - (NSNumber *)lks_imageViewOidIfHasImage { 22 | if (!self.image) { 23 | return nil; 24 | } 25 | unsigned long oid = [self lks_registerOid]; 26 | return @(oid); 27 | } 28 | 29 | @end 30 | 31 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 32 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UILabel+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UILabel+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UILabel (LookinServer) 14 | 15 | @property(nonatomic, assign) CGFloat lks_fontSize; 16 | 17 | - (NSString *)lks_fontName; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UILabel+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UILabel+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UILabel+LookinServer.h" 12 | 13 | @implementation UILabel (LookinServer) 14 | 15 | - (CGFloat)lks_fontSize { 16 | return self.font.pointSize; 17 | } 18 | - (void)setLks_fontSize:(CGFloat)lks_fontSize { 19 | UIFont *font = [self.font fontWithSize:lks_fontSize]; 20 | self.font = font; 21 | } 22 | 23 | - (NSString *)lks_fontName { 24 | return self.font.fontName; 25 | } 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITableView+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITableView+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/9/5. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UITableView (LookinServer) 14 | 15 | - (NSArray *)lks_numberOfRows; 16 | 17 | @end 18 | 19 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 20 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITableView+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITableView+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/9/5. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UITableView+LookinServer.h" 12 | #import "LookinServerDefines.h" 13 | 14 | @implementation UITableView (LookinServer) 15 | 16 | - (NSArray *)lks_numberOfRows { 17 | NSUInteger sectionsCount = MIN(self.numberOfSections, 10); 18 | NSArray *rowsCount = [NSArray lookin_arrayWithCount:sectionsCount block:^id(NSUInteger idx) { 19 | return @([self numberOfRowsInSection:idx]); 20 | }]; 21 | if (rowsCount.count == 0) { 22 | return nil; 23 | } 24 | return rowsCount; 25 | } 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITextField+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITextField+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UITextField (LookinServer) 14 | 15 | @property(nonatomic, assign) CGFloat lks_fontSize; 16 | 17 | - (NSString *)lks_fontName; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITextField+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITextField+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UITextField+LookinServer.h" 12 | 13 | @implementation UITextField (LookinServer) 14 | 15 | - (CGFloat)lks_fontSize { 16 | return self.font.pointSize; 17 | } 18 | - (void)setLks_fontSize:(CGFloat)lks_fontSize { 19 | UIFont *font = [self.font fontWithSize:lks_fontSize]; 20 | self.font = font; 21 | } 22 | 23 | - (NSString *)lks_fontName { 24 | return self.font.fontName; 25 | } 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITextView+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITextView+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UITextView (LookinServer) 14 | 15 | @property(nonatomic, assign) CGFloat lks_fontSize; 16 | 17 | - (NSString *)lks_fontName; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UITextView+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UITextView+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/26. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UITextView+LookinServer.h" 12 | 13 | @implementation UITextView (LookinServer) 14 | 15 | - (CGFloat)lks_fontSize { 16 | return self.font.pointSize; 17 | } 18 | - (void)setLks_fontSize:(CGFloat)lks_fontSize { 19 | UIFont *font = [self.font fontWithSize:lks_fontSize]; 20 | self.font = font; 21 | } 22 | 23 | - (NSString *)lks_fontName { 24 | return self.font.fontName; 25 | } 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIView+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIView+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/3/19. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | #import 13 | 14 | @interface UIView (LookinServer) 15 | 16 | /// 如果 myViewController.view = myView,则可以通过 myView 的 lks_findHostViewController 方法找到 myViewController 17 | - (UIViewController *)lks_findHostViewController; 18 | 19 | /// 是否是 UITabBar 的 childrenView,如果是的话,则截图时需要强制使用 renderInContext: 的方式而非 drawViewHierarchyInRect:afterScreenUpdates: 否则在 iOS 13 上获取到的图像是空的不知道为什么 20 | @property(nonatomic, assign) BOOL lks_isChildrenViewOfTabBar; 21 | 22 | /// point 是相对于 receiver 自身的坐标系 23 | - (UIView *)lks_subviewAtPoint:(CGPoint)point preferredClasses:(NSArray *)preferredClasses; 24 | 25 | - (CGFloat)lks_bestWidth; 26 | - (CGFloat)lks_bestHeight; 27 | - (CGSize)lks_bestSize; 28 | 29 | @property(nonatomic, assign) float lks_horizontalContentHuggingPriority; 30 | @property(nonatomic, assign) float lks_verticalContentHuggingPriority; 31 | 32 | @property(nonatomic, assign) float lks_horizontalContentCompressionResistancePriority; 33 | @property(nonatomic, assign) float lks_verticalContentCompressionResistancePriority; 34 | 35 | /// 遍历全局的 view 并给他们设置 lks_involvedRawConstraints 属性 36 | + (void)lks_rebuildGlobalInvolvedRawConstraints; 37 | /// 该属性保存了牵扯到当前 view 的所有 constraints,包括那些没有生效的 38 | @property(nonatomic, strong) NSMutableArray *lks_involvedRawConstraints; 39 | 40 | - (NSArray *> *)lks_constraints; 41 | 42 | @end 43 | 44 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 45 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIViewController+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIViewController+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/22. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIViewController (LookinServer) 14 | 15 | + (UIViewController *)lks_visibleViewController; 16 | 17 | @end 18 | 19 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 20 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIViewController+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIViewController+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/22. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UIViewController+LookinServer.h" 12 | #import "UIView+LookinServer.h" 13 | #import 14 | #import "LKS_MultiplatformAdapter.h" 15 | 16 | @implementation UIViewController (LookinServer) 17 | 18 | + (nullable UIViewController *)lks_visibleViewController { 19 | 20 | UIViewController *rootViewController = [LKS_MultiplatformAdapter keyWindow].rootViewController; 21 | UIViewController *visibleViewController = [rootViewController lks_visibleViewControllerIfExist]; 22 | return visibleViewController; 23 | } 24 | 25 | - (UIViewController *)lks_visibleViewControllerIfExist { 26 | 27 | if (self.presentedViewController) { 28 | return [self.presentedViewController lks_visibleViewControllerIfExist]; 29 | } 30 | 31 | if ([self isKindOfClass:[UINavigationController class]]) { 32 | return [((UINavigationController *)self).visibleViewController lks_visibleViewControllerIfExist]; 33 | } 34 | 35 | if ([self isKindOfClass:[UITabBarController class]]) { 36 | return [((UITabBarController *)self).selectedViewController lks_visibleViewControllerIfExist]; 37 | } 38 | 39 | if (self.isViewLoaded && !self.view.hidden && self.view.alpha > 0.01) { 40 | return self; 41 | } else { 42 | return nil; 43 | } 44 | } 45 | 46 | @end 47 | 48 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 49 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIVisualEffectView+LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIVisualEffectView+LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/10/8. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface UIVisualEffectView (LookinServer) 14 | 15 | - (void)setLks_blurEffectStyleNumber:(NSNumber *)lks_blurEffectStyleNumber; 16 | 17 | - (NSNumber *)lks_blurEffectStyleNumber; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Category/UIVisualEffectView+LookinServer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // UIVisualEffectView+LookinServer.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/10/8. 8 | // https://lookin.work 9 | // 10 | 11 | #import "UIVisualEffectView+LookinServer.h" 12 | #import "UIBlurEffect+LookinServer.h" 13 | 14 | @implementation UIVisualEffectView (LookinServer) 15 | 16 | - (void)setLks_blurEffectStyleNumber:(NSNumber *)lks_blurEffectStyleNumber { 17 | UIBlurEffectStyle style = [lks_blurEffectStyleNumber integerValue]; 18 | UIBlurEffect *effect = [UIBlurEffect effectWithStyle:style]; 19 | self.effect = effect; 20 | } 21 | 22 | - (NSNumber *)lks_blurEffectStyleNumber { 23 | UIVisualEffect *effect = self.effect; 24 | if (![effect isKindOfClass:[UIBlurEffect class]]) { 25 | return nil; 26 | } 27 | UIBlurEffect *blurEffect = (UIBlurEffect *)effect; 28 | return blurEffect.lks_effectStyleNumber; 29 | } 30 | 31 | @end 32 | 33 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 34 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/LKS_ConnectionManager.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/8/5. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | extern NSString *const LKS_ConnectionDidEndNotificationName; 14 | 15 | @class LookinConnectionResponseAttachment; 16 | 17 | @interface LKS_ConnectionManager : NSObject 18 | 19 | + (instancetype)sharedInstance; 20 | 21 | @property(nonatomic, assign) BOOL applicationIsActive; 22 | 23 | - (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag; 24 | 25 | - (void)pushData:(NSObject *)data type:(uint32_t)type; 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/LKS_RequestHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_RequestHandler.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/1/15. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface LKS_RequestHandler : NSObject 14 | 15 | - (BOOL)canHandleRequestType:(uint32_t)requestType; 16 | 17 | - (void)handleRequestType:(uint32_t)requestType tag:(uint32_t)tag object:(id)object; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/RequestHandler/LKS_AttrModificationPatchHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_AttrModificationPatchHandler.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/12. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @class LookinDisplayItemDetail; 14 | 15 | @interface LKS_AttrModificationPatchHandler : NSObject 16 | 17 | /** 18 | @param oids 数组内 idx 较小的应该为 displayItems 里的 subItem,idx 较大的应该为 superItem 19 | @param lowImageQuality 是否采用低图像质量 20 | @param block 该 block 会被多次调用,其中 tasksTotalCount 是总的调用次数(即可被用来作为 TotalResponseCount) 21 | */ 22 | + (void)handleLayerOids:(NSArray *)oids lowImageQuality:(BOOL)lowImageQuality block:(void (^)(LookinDisplayItemDetail *detail, NSUInteger tasksTotalCount, NSError *error))block; 23 | 24 | @end 25 | 26 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 27 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/RequestHandler/LKS_AttrModificationPatchHandler.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_AttrModificationPatchHandler.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/12. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LKS_AttrModificationPatchHandler.h" 12 | #import "LookinDisplayItemDetail.h" 13 | #import "LookinServerDefines.h" 14 | 15 | @implementation LKS_AttrModificationPatchHandler 16 | 17 | + (void)handleLayerOids:(NSArray *)oids lowImageQuality:(BOOL)lowImageQuality block:(void (^)(LookinDisplayItemDetail *detail, NSUInteger tasksTotalCount, NSError *error))block { 18 | if (!block) { 19 | NSAssert(NO, @""); 20 | return; 21 | } 22 | if (![oids isKindOfClass:[NSArray class]]) { 23 | block(nil, 1, LookinErr_Inner); 24 | return; 25 | } 26 | 27 | [oids enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 28 | unsigned long oid = [obj unsignedLongValue]; 29 | LookinDisplayItemDetail *detail = [LookinDisplayItemDetail new]; 30 | detail.displayItemOid = oid; 31 | 32 | CALayer *layer = (CALayer *)[NSObject lks_objectWithOid:oid]; 33 | if (![layer isKindOfClass:[CALayer class]]) { 34 | block(nil, idx + 1, LookinErr_ObjNotFound); 35 | *stop = YES; 36 | return; 37 | } 38 | 39 | if (idx == 0) { 40 | detail.soloScreenshot = [layer lks_soloScreenshotWithLowQuality:lowImageQuality]; 41 | detail.groupScreenshot = [layer lks_groupScreenshotWithLowQuality:lowImageQuality]; 42 | } else { 43 | detail.groupScreenshot = [layer lks_groupScreenshotWithLowQuality:lowImageQuality]; 44 | } 45 | block(detail, oids.count, nil); 46 | }]; 47 | } 48 | 49 | @end 50 | 51 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 52 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/RequestHandler/LKS_CustomAttrModificationHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LKS_CustomAttrModificationHandler.h 4 | // LookinServer 5 | // 6 | // Created by likaimacbookhome on 2023/11/4. 7 | // 8 | 9 | #import 10 | #import "LookinCustomAttrModification.h" 11 | 12 | @interface LKS_CustomAttrModificationHandler : NSObject 13 | 14 | /// 返回值表示是否修改成功(有成功调用 setter block 就算成功) 15 | + (BOOL)handleModification:(LookinCustomAttrModification *)modification; 16 | 17 | @end 18 | 19 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 20 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/RequestHandler/LKS_HierarchyDetailsHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_HierarchyDetailsHandler.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/20. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @class LookinDisplayItemDetail, LookinStaticAsyncUpdateTasksPackage; 14 | 15 | typedef void (^LKS_HierarchyDetailsHandler_ProgressBlock)(NSArray *details); 16 | typedef void (^LKS_HierarchyDetailsHandler_FinishBlock)(void); 17 | 18 | @interface LKS_HierarchyDetailsHandler : NSObject 19 | 20 | /// packages 会按照 idx 从小到大的顺序被执行 21 | /// 全部任务完成时,finishBlock 会被调用 22 | /// 如果调用了 cancel,则 finishBlock 不会被执行 23 | - (void)startWithPackages:(NSArray *)packages block:(LKS_HierarchyDetailsHandler_ProgressBlock)progressBlock finishedBlock:(LKS_HierarchyDetailsHandler_FinishBlock)finishBlock; 24 | 25 | /// 取消所有任务 26 | - (void)cancel; 27 | 28 | @end 29 | 30 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 31 | -------------------------------------------------------------------------------- /Src/Main/Server/Connection/RequestHandler/LKS_InbuiltAttrModificationHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_InbuiltAttrModificationHandler.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/12. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @class LookinAttributeModification, LookinDisplayItemDetail, LookinStaticAsyncUpdateTask; 14 | 15 | @interface LKS_InbuiltAttrModificationHandler : NSObject 16 | 17 | + (void)handleModification:(LookinAttributeModification *)modification completion:(void (^)(LookinDisplayItemDetail *data, NSError *error))completion; 18 | 19 | + (void)handlePatchWithTasks:(NSArray *)tasks block:(void (^)(LookinDisplayItemDetail *data))block; 20 | 21 | @end 22 | 23 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 24 | -------------------------------------------------------------------------------- /Src/Main/Server/LookinServer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinServer.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/7/20. 8 | // https://lookin.work 9 | // 10 | 11 | #ifndef LookinServer_h 12 | #define LookinServer_h 13 | 14 | 15 | #endif /* LookinServer_h */ 16 | 17 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 18 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKSConfigManager.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKSConfigManager.h 5 | // LookinServer 6 | // 7 | // Created by likai.123 on 2023/1/10. 8 | // 9 | 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface LKSConfigManager : NSObject 15 | 16 | + (NSArray *)collapsedClassList; 17 | 18 | + (NSDictionary *)colorAlias; 19 | 20 | + (BOOL)shouldCaptureScreenshotOfLayer:(CALayer *)layer; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | 26 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 27 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_AttrGroupsMaker.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_AttrGroupsMaker.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/6/6. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | @class LookinAttributesGroup; 14 | 15 | @interface LKS_AttrGroupsMaker : NSObject 16 | 17 | + (NSArray *)attrGroupsForLayer:(CALayer *)layer; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_CustomAttrGroupsMaker.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LKS_CustomAttrGroupsMaker.h 4 | // LookinServer 5 | // 6 | // Created by LikaiMacStudioWork on 2023/10/31. 7 | // 8 | 9 | #import "LookinDefines.h" 10 | 11 | @class LookinAttributesGroup; 12 | 13 | @interface LKS_CustomAttrGroupsMaker : NSObject 14 | 15 | - (instancetype)initWithLayer:(CALayer *)layer; 16 | 17 | - (void)execute; 18 | 19 | - (NSArray *)getGroups; 20 | - (NSString *)getCustomDisplayTitle; 21 | - (NSString *)getDanceUISource; 22 | 23 | + (NSArray *)makeGroupsFromRawProperties:(NSArray *)rawProperties saveCustomSetter:(BOOL)saveCustomSetter; 24 | 25 | @end 26 | 27 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 28 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_CustomAttrSetterManager.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LKS_CustomAttrSetterManager.h 4 | // LookinServer 5 | // 6 | // Created by likai.123 on 2023/11/4. 7 | // 8 | 9 | #import 10 | 11 | typedef void(^LKS_StringSetter)(NSString *); 12 | typedef void(^LKS_NumberSetter)(NSNumber *); 13 | typedef void(^LKS_BoolSetter)(BOOL); 14 | typedef void(^LKS_ColorSetter)(UIColor *); 15 | typedef void(^LKS_EnumSetter)(NSString *); 16 | typedef void(^LKS_RectSetter)(CGRect); 17 | typedef void(^LKS_SizeSetter)(CGSize); 18 | typedef void(^LKS_PointSetter)(CGPoint); 19 | typedef void(^LKS_InsetsSetter)(UIEdgeInsets); 20 | 21 | @interface LKS_CustomAttrSetterManager : NSObject 22 | 23 | + (instancetype)sharedInstance; 24 | 25 | - (void)removeAll; 26 | 27 | - (void)saveStringSetter:(LKS_StringSetter)setter uniqueID:(NSString *)uniqueID; 28 | - (LKS_StringSetter)getStringSetterWithID:(NSString *)uniqueID; 29 | 30 | - (void)saveNumberSetter:(LKS_NumberSetter)setter uniqueID:(NSString *)uniqueID; 31 | - (LKS_NumberSetter)getNumberSetterWithID:(NSString *)uniqueID; 32 | 33 | - (void)saveBoolSetter:(LKS_BoolSetter)setter uniqueID:(NSString *)uniqueID; 34 | - (LKS_BoolSetter)getBoolSetterWithID:(NSString *)uniqueID; 35 | 36 | - (void)saveColorSetter:(LKS_ColorSetter)setter uniqueID:(NSString *)uniqueID; 37 | - (LKS_ColorSetter)getColorSetterWithID:(NSString *)uniqueID; 38 | 39 | - (void)saveEnumSetter:(LKS_EnumSetter)setter uniqueID:(NSString *)uniqueID; 40 | - (LKS_EnumSetter)getEnumSetterWithID:(NSString *)uniqueID; 41 | 42 | - (void)saveRectSetter:(LKS_RectSetter)setter uniqueID:(NSString *)uniqueID; 43 | - (LKS_RectSetter)getRectSetterWithID:(NSString *)uniqueID; 44 | 45 | - (void)saveSizeSetter:(LKS_SizeSetter)setter uniqueID:(NSString *)uniqueID; 46 | - (LKS_SizeSetter)getSizeSetterWithID:(NSString *)uniqueID; 47 | 48 | - (void)savePointSetter:(LKS_PointSetter)setter uniqueID:(NSString *)uniqueID; 49 | - (LKS_PointSetter)getPointSetterWithID:(NSString *)uniqueID; 50 | 51 | - (void)saveInsetsSetter:(LKS_InsetsSetter)setter uniqueID:(NSString *)uniqueID; 52 | - (LKS_InsetsSetter)getInsetsSetterWithID:(NSString *)uniqueID; 53 | 54 | @end 55 | 56 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 57 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_CustomDisplayItemsMaker.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_CustomDisplayItemsMaker.h 5 | // LookinServer 6 | // 7 | // Created by likai.123 on 2023/11/1. 8 | // 9 | 10 | #import 11 | 12 | @class LookinDisplayItem; 13 | 14 | @interface LKS_CustomDisplayItemsMaker : NSObject 15 | 16 | - (instancetype)initWithLayer:(CALayer *)layer saveAttrSetter:(BOOL)saveAttrSetter; 17 | 18 | - (NSArray *)make; 19 | 20 | @end 21 | 22 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 23 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_EventHandlerMaker.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_EventHandlerMaker.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/8/7. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | @class LookinEventHandler; 14 | 15 | @interface LKS_EventHandlerMaker : NSObject 16 | 17 | + (NSArray *)makeForView:(UIView *)view; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_ExportManager.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_ExportManager.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/5/13. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface LKS_ExportManager : NSObject 14 | 15 | + (instancetype)sharedInstance; 16 | 17 | - (void)exportAndShare; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_GestureTargetActionsSearcher.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_GestureTargetActionsSearcher.h 5 | // LookinServer 6 | // 7 | // Created by likai.123 on 2023/9/11. 8 | // 9 | 10 | #import 11 | 12 | @class LookinTwoTuple; 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface LKS_GestureTargetActionsSearcher : NSObject 17 | 18 | /// 返回一个 UIGestureRecognizer 实例身上绑定的 target & action 信息 19 | /// tuple.first => LookinWeakContainer(包裹着 target),tuple.second => action(方法名字符串) 20 | + (NSArray *)getTargetActionsFromRecognizer:(UIGestureRecognizer *)recognizer; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | 26 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 27 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_GestureTargetActionsSearcher.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_GestureTargetActionsSearcher.m 5 | // LookinServer 6 | // 7 | // Created by likai.123 on 2023/9/11. 8 | // 9 | 10 | #import "LKS_GestureTargetActionsSearcher.h" 11 | #import 12 | #import "NSArray+Lookin.h" 13 | #import "LookinTuple.h" 14 | #import "LookinWeakContainer.h" 15 | 16 | @implementation LKS_GestureTargetActionsSearcher 17 | 18 | + (NSArray *)getTargetActionsFromRecognizer:(UIGestureRecognizer *)recognizer { 19 | if (!recognizer) { 20 | return @[]; 21 | } 22 | // KVC 要放到 try catch 里面防止 Crash 23 | @try { 24 | NSArray* targetsList = [recognizer valueForKey:@"_targets"]; 25 | if (!targetsList || targetsList.count == 0) { 26 | return @[]; 27 | } 28 | // 数组元素对象是 UIGestureRecognizerTarget* 29 | // 这个元素有两个属性,一个是名为 _target 的属性指向某个实例,另一个是名为 _action 的属性保存一个 SEL 30 | NSArray* ret = [targetsList lookin_map:^id(NSUInteger idx, id targetBox) { 31 | id targetObj = [targetBox valueForKey:@"_target"]; 32 | if (!targetObj) { 33 | return nil; 34 | } 35 | SEL action = ((SEL (*)(id, Ivar))object_getIvar)(targetBox, class_getInstanceVariable([targetBox class], "_action")); 36 | 37 | LookinTwoTuple* tuple = [LookinTwoTuple new]; 38 | tuple.first = [LookinWeakContainer containerWithObject:targetObj]; 39 | tuple.second = (action == NULL ? @"NULL" : NSStringFromSelector(action)); 40 | return tuple; 41 | }]; 42 | return ret; 43 | } 44 | @catch (NSException * e) { 45 | NSLog(@"LookinServer - %@", e); 46 | return @[]; 47 | } 48 | } 49 | 50 | @end 51 | 52 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 53 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_Helper.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_Helper.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/7/20. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import 16 | 17 | #define LKS_Localized(stringKey) NSLocalizedStringFromTableInBundle(stringKey, nil, [NSBundle bundleForClass:self.class], nil) 18 | 19 | @interface LKS_Helper : NSObject 20 | 21 | /// 如果 object 为 nil 则返回字符串 “nil”,否则返回字符串格式类似于 (UIView *) 22 | + (NSString *)descriptionOfObject:(id)object; 23 | 24 | /// 返回当前的bundle 25 | + (NSBundle *)bundle; 26 | 27 | @end 28 | 29 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 30 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_Helper.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_Helper.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/7/20. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LKS_Helper.h" 12 | #import "NSObject+LookinServer.h" 13 | 14 | @implementation LKS_Helper 15 | 16 | + (NSString *)descriptionOfObject:(id)object { 17 | if (!object) { 18 | return @"nil"; 19 | } 20 | NSString *className = NSStringFromClass([object class]); 21 | return [NSString stringWithFormat:@"(%@ *)", className]; 22 | } 23 | 24 | + (NSBundle *)bundle { 25 | static id bundle = nil; 26 | if (bundle != nil) { 27 | #ifdef SPM_RESOURCE_BUNDLE_IDENTIFITER 28 | bundle = [NSBundle bundleWithIdentifier:SPM_RESOURCE_BUNDLE_IDENTIFITER]; 29 | #else 30 | bundle = [NSBundle bundleForClass:self.class]; 31 | #endif 32 | } 33 | return bundle; 34 | } 35 | 36 | @end 37 | 38 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 39 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_HierarchyDisplayItemsMaker.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_HierarchyDisplayItemsMaker.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/2/19. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinDefines.h" 14 | 15 | @class LookinDisplayItem; 16 | 17 | @interface LKS_HierarchyDisplayItemsMaker : NSObject 18 | 19 | /// @param hasScreenshots 是否包含 soloScreenshots 和 groupScreenshot 属性 20 | /// @param hasAttrList 是否包含 attributesGroupList 属性 21 | /// @param lowQuality screenshots 是否为低质量(当 hasScreenshots 为 NO 时,该属性无意义) 22 | /// @param readCustomInfo 是否读取 lookin_customDebugInfos,比如低版本的 Lookin 发请求时,就无需读取(因为 Lookin 解析不了、还可能出 Bug) 23 | /// @param saveCustomSetter 是否要读取并保存用户给 attribute 配置的 custom setter 24 | + (NSArray *)itemsWithScreenshots:(BOOL)hasScreenshots attrList:(BOOL)hasAttrList lowImageQuality:(BOOL)lowQuality readCustomInfo:(BOOL)readCustomInfo saveCustomSetter:(BOOL)saveCustomSetter; 25 | 26 | /// 把 layer 的 sublayers 转换为 displayItem 数组并返回 27 | + (NSArray *)subitemsOfLayer:(CALayer *)layer; 28 | 29 | @end 30 | 31 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 32 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_MultiplatformAdapter.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LKS_MultiplatformAdapter.h 4 | // 5 | // 6 | // Created by nixjiang on 2024/3/12. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface LKS_MultiplatformAdapter : NSObject 15 | 16 | + (UIWindow *)keyWindow; 17 | 18 | + (NSArray *)allWindows; 19 | 20 | + (CGRect)mainScreenBounds; 21 | 22 | + (CGFloat)mainScreenScale; 23 | 24 | + (BOOL)isiPad; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | 30 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 31 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_MultiplatformAdapter.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LKS_MultiplatformAdapter.m 4 | // 5 | // 6 | // Created by nixjiang on 2024/3/12. 7 | // 8 | 9 | #import "LKS_MultiplatformAdapter.h" 10 | #import 11 | 12 | @implementation LKS_MultiplatformAdapter 13 | 14 | + (BOOL)isiPad { 15 | static BOOL s_isiPad = NO; 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | NSString *nsModel = [UIDevice currentDevice].model; 20 | s_isiPad = [nsModel hasPrefix:@"iPad"]; 21 | }); 22 | 23 | return s_isiPad; 24 | } 25 | 26 | + (CGRect)mainScreenBounds { 27 | #if TARGET_OS_VISION 28 | return [LKS_MultiplatformAdapter getFirstActiveWindowScene].coordinateSpace.bounds; 29 | #else 30 | return [UIScreen mainScreen].bounds; 31 | #endif 32 | } 33 | 34 | + (CGFloat)mainScreenScale { 35 | #if TARGET_OS_VISION 36 | return 2.f; 37 | #else 38 | return [UIScreen mainScreen].scale; 39 | #endif 40 | } 41 | 42 | #if TARGET_OS_VISION 43 | + (UIWindowScene *)getFirstActiveWindowScene { 44 | for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { 45 | if (![scene isKindOfClass:UIWindowScene.class]) { 46 | continue; 47 | } 48 | UIWindowScene *windowScene = (UIWindowScene *)scene; 49 | if (windowScene.activationState == UISceneActivationStateForegroundActive) { 50 | return windowScene; 51 | } 52 | } 53 | return nil; 54 | } 55 | #endif 56 | 57 | + (UIWindow *)keyWindow { 58 | #if TARGET_OS_VISION 59 | return [self getFirstActiveWindowScene].keyWindow; 60 | #else 61 | return [UIApplication sharedApplication].keyWindow; 62 | #endif 63 | } 64 | 65 | + (NSArray *)allWindows { 66 | #if TARGET_OS_VISION 67 | NSMutableArray *windows = [NSMutableArray new]; 68 | for (UIScene *scene in 69 | UIApplication.sharedApplication.connectedScenes) { 70 | if (![scene isKindOfClass:UIWindowScene.class]) { 71 | continue; 72 | } 73 | UIWindowScene *windowScene = (UIWindowScene *)scene; 74 | [windows addObjectsFromArray:windowScene.windows]; 75 | 76 | // 以UIModalPresentationFormSheet形式展示的页面由系统私有window承载,不出现在scene.windows,不过可以从scene.keyWindow中获取 77 | if (![windows containsObject:windowScene.keyWindow]) { 78 | if (![NSStringFromClass(windowScene.keyWindow.class) containsString:@"HUD"]) { 79 | [windows addObject:windowScene.keyWindow]; 80 | } 81 | } 82 | } 83 | 84 | return [windows copy]; 85 | #else 86 | return [[UIApplication sharedApplication].windows copy]; 87 | #endif 88 | } 89 | 90 | @end 91 | 92 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 93 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_ObjectRegistry.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_ObjectRegistry.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/21. 8 | // https://lookin.work 9 | // 10 | 11 | #import 12 | 13 | @interface LKS_ObjectRegistry : NSObject 14 | 15 | + (instancetype)sharedInstance; 16 | 17 | - (unsigned long)addObject:(NSObject *)object; 18 | 19 | - (NSObject *)objectWithOid:(unsigned long)oid; 20 | 21 | @end 22 | 23 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 24 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_ObjectRegistry.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_ObjectRegistry.m 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/4/21. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LKS_ObjectRegistry.h" 12 | #import 13 | 14 | @interface LKS_ObjectRegistry () 15 | 16 | @property(nonatomic, strong) NSPointerArray *data; 17 | 18 | @end 19 | 20 | @implementation LKS_ObjectRegistry 21 | 22 | + (instancetype)sharedInstance { 23 | static dispatch_once_t onceToken; 24 | static LKS_ObjectRegistry *instance = nil; 25 | dispatch_once(&onceToken,^{ 26 | instance = [[super allocWithZone:NULL] init]; 27 | }); 28 | return instance; 29 | } 30 | 31 | + (id)allocWithZone:(struct _NSZone *)zone{ 32 | return [self sharedInstance]; 33 | } 34 | 35 | - (instancetype)init { 36 | if (self = [super init]) { 37 | self.data = [NSPointerArray weakObjectsPointerArray]; 38 | // index 为 0 用 Null 填充 39 | self.data.count = 1; 40 | } 41 | return self; 42 | } 43 | 44 | - (unsigned long)addObject:(NSObject *)object { 45 | if (!object) { 46 | return 0; 47 | } 48 | [self.data addPointer:(void *)object]; 49 | return self.data.count - 1; 50 | } 51 | 52 | - (NSObject *)objectWithOid:(unsigned long)oid { 53 | if (self.data.count <= oid) { 54 | return nil; 55 | } 56 | id object = [self.data pointerAtIndex:oid]; 57 | return object; 58 | } 59 | 60 | @end 61 | 62 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 63 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LKS_TraceManager.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LKS_TraceManager.h 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2019/5/5. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @class LookinIvarTrace; 16 | 17 | @interface LKS_TraceManager : NSObject 18 | 19 | + (instancetype)sharedInstance; 20 | 21 | - (void)reload; 22 | 23 | - (void)addSearchTarger:(id)target; 24 | 25 | @end 26 | 27 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 28 | -------------------------------------------------------------------------------- /Src/Main/Server/Others/LookinServerDefines.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinServer_PrefixHeader.pch 5 | // LookinServer 6 | // 7 | // Created by Li Kai on 2018/12/21. 8 | // https://lookin.work 9 | // 10 | 11 | #import "TargetConditionals.h" 12 | #import "LookinDefines.h" 13 | #import "LKS_Helper.h" 14 | #import "NSObject+LookinServer.h" 15 | #import "NSArray+Lookin.h" 16 | #import "NSSet+Lookin.h" 17 | #import "CALayer+Lookin.h" 18 | #import "UIView+LookinServer.h" 19 | #import "CALayer+LookinServer.h" 20 | #import "NSObject+Lookin.h" 21 | #import "NSString+Lookin.h" 22 | 23 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 24 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/CALayer+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // CALayer+Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/8/4. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import 16 | 17 | @interface CALayer (Lookin) 18 | 19 | - (void)lookin_removeImplicitAnimations; 20 | 21 | @end 22 | 23 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 24 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/Color+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Color+Lookin.h 5 | // LookinShared 6 | // 7 | // Created by 李凯 on 2022/4/2. 8 | // 9 | 10 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | 14 | #elif TARGET_OS_MAC 15 | 16 | @interface NSColor (Lookin) 17 | 18 | + (instancetype)lookin_colorFromRGBAComponents:(NSArray *)components; 19 | 20 | - (NSArray *)lookin_rgbaComponents; 21 | 22 | @end 23 | 24 | #endif 25 | 26 | 27 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 28 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/Color+Lookin.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Color+Lookin.m 5 | // LookinShared 6 | // 7 | // Created by 李凯 on 2022/4/2. 8 | // 9 | 10 | #import "Image+Lookin.h" 11 | 12 | #if TARGET_OS_IPHONE 13 | 14 | #elif TARGET_OS_MAC 15 | 16 | @implementation NSColor (Lookin) 17 | 18 | + (instancetype)lookin_colorFromRGBAComponents:(NSArray *)components { 19 | if (!components) { 20 | return nil; 21 | } 22 | if (components.count != 4) { 23 | NSAssert(NO, @""); 24 | return nil; 25 | } 26 | NSColor *color = [NSColor colorWithRed:components[0].doubleValue green:components[1].doubleValue blue:components[2].doubleValue alpha:components[3].doubleValue]; 27 | return color; 28 | } 29 | 30 | - (NSArray *)lookin_rgbaComponents { 31 | NSColor *rgbColor = [self colorUsingColorSpace:NSColorSpace.sRGBColorSpace]; 32 | CGFloat r, g, b, a; 33 | [rgbColor getRed:&r green:&g blue:&b alpha:&a]; 34 | NSArray *rgba = @[@(r), @(g), @(b), @(a)]; 35 | return rgba; 36 | } 37 | 38 | @end 39 | 40 | #endif 41 | 42 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 43 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/Image+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Image+Lookin.h 5 | // LookinShared 6 | // 7 | // Created by 李凯 on 2022/4/2. 8 | // 9 | 10 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | 14 | #elif TARGET_OS_MAC 15 | 16 | @interface NSImage (LookinClient) 17 | 18 | - (NSData *)lookin_data; 19 | 20 | @end 21 | 22 | #endif 23 | 24 | 25 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 26 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/Image+Lookin.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Image+Lookin.m 5 | // LookinShared 6 | // 7 | // Created by 李凯 on 2022/4/2. 8 | // 9 | 10 | #import "Image+Lookin.h" 11 | 12 | #if TARGET_OS_IPHONE 13 | 14 | #elif TARGET_OS_MAC 15 | 16 | @implementation NSImage (LookinClient) 17 | 18 | - (NSData *)lookin_data { 19 | return [self TIFFRepresentation]; 20 | } 21 | 22 | @end 23 | 24 | #endif 25 | 26 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 27 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/NSArray+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSArray+Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/9/3. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import 16 | #import 17 | 18 | @interface NSArray<__covariant ValueType> (Lookin) 19 | 20 | /** 21 | 初始化一个新的 NSArray 并返回,新数组的长度为 count,如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则会舍弃多余的元素,被舍弃的元素会作为参数传入 removeBlock。最终,新数组的所有元素均会作为参数被传入 doBlock。 22 | */ 23 | - (NSArray *)lookin_resizeWithCount:(NSUInteger)count add:(ValueType (^)(NSUInteger idx))addBlock remove:(void (^)(NSUInteger idx, ValueType obj))removeBlock doNext:(void (^)(NSUInteger idx, ValueType obj))doBlock __attribute__((warn_unused_result)); 24 | 25 | + (NSArray *)lookin_arrayWithCount:(NSUInteger)count block:(id (^)(NSUInteger idx))block; 26 | 27 | /** 28 | 检查 index 位置是否有元素存在 29 | */ 30 | - (BOOL)lookin_hasIndex:(NSInteger)index; 31 | 32 | - (NSArray *)lookin_map:(id (^)(NSUInteger idx, ValueType value))block; 33 | 34 | - (NSArray *)lookin_filter:(BOOL (^)( ValueType obj))block; 35 | 36 | - (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block; 37 | 38 | /// 返回最后一个 block 返回 YES 的元素 39 | - (ValueType)lookin_lastFiltered:(BOOL (^)(ValueType obj))block; 40 | 41 | - (id)lookin_reduce:(id (^)(id accumulator, NSUInteger idx, ValueType obj))block; 42 | 43 | - (CGFloat)lookin_reduceCGFloat:(CGFloat (^)(CGFloat accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(CGFloat)initialAccumlator; 44 | - (NSInteger)lookin_reduceInteger:(NSInteger (^)(NSInteger accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(NSInteger)initialAccumlator; 45 | 46 | - (BOOL)lookin_all:(BOOL (^)(ValueType obj))block; 47 | 48 | - (BOOL)lookin_any:(BOOL (^)(ValueType obj))block; 49 | 50 | - (NSArray *)lookin_arrayByRemovingObject:(ValueType)obj; 51 | 52 | - (NSArray *)lookin_nonredundantArray; 53 | 54 | - (ValueType)lookin_safeObjectAtIndex:(NSInteger)idx; 55 | 56 | /// 字符串长度从短到长,即 length 小的字符串的 idx 更小 57 | - (NSArray *)lookin_sortedArrayByStringLength; 58 | 59 | @end 60 | 61 | @interface NSMutableArray (Lookin) 62 | 63 | /** 64 | 如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则多余的元素会被作为参数传入 notDequeued。然后从 idx 为 0 算起,前 count 个元素会被作为参数传入 doBlock 65 | */ 66 | - (void)lookin_dequeueWithCount:(NSUInteger)count add:(ValueType (^)(NSUInteger idx))addBlock notDequeued:(void (^)(NSUInteger idx, ValueType obj))notDequeuedBlock doNext:(void (^)(NSUInteger idx, ValueType obj))doBlock; 67 | 68 | - (void)lookin_removeObjectsPassingTest:(BOOL (^)(NSUInteger idx, ValueType obj))block; 69 | 70 | @end 71 | 72 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 73 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/NSObject+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSObject+Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/12/22. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import 16 | #import "LookinCodingValueType.h" 17 | 18 | @interface NSObject (Lookin) 19 | 20 | #pragma mark - Data Bind 21 | 22 | /** 23 | 给对象绑定上另一个对象以供后续取出使用,如果 object 传入 nil 则会清除该 key 之前绑定的对象 24 | 25 | @attention 被绑定的对象会被 strong 强引用 26 | @note 内部是使用 objc_setAssociatedObject / objc_getAssociatedObject 来实现 27 | 28 | @code 29 | - (UITableViewCell *)cellForIndexPath:(NSIndexPath *)indexPath { 30 | // 1)在这里给 button 绑定上 indexPath 对象 31 | [cell lookin_bindObject:indexPath forKey:@"indexPath"]; 32 | } 33 | 34 | - (void)didTapButton:(UIButton *)button { 35 | // 2)在这里取出被点击的 button 的 indexPath 对象 36 | NSIndexPath *indexPathTapped = [button lookin_getBindObjectForKey:@"indexPath"]; 37 | } 38 | @endcode 39 | */ 40 | - (void)lookin_bindObject:(id)object forKey:(NSString *)key; 41 | 42 | /** 43 | 给对象绑定上另一个对象以供后续取出使用,但相比于 lookin_bindObject:forKey:,该方法不会 strong 强引用传入的 object 44 | */ 45 | - (void)lookin_bindObjectWeakly:(id)object forKey:(NSString *)key; 46 | 47 | /** 48 | 取出之前使用 bind 方法绑定的对象 49 | */ 50 | - (id)lookin_getBindObjectForKey:(NSString *)key; 51 | 52 | /** 53 | 给对象绑定上一个 double 值以供后续取出使用 54 | */ 55 | - (void)lookin_bindDouble:(double)doubleValue forKey:(NSString *)key; 56 | 57 | /** 58 | 取出之前用 lookin_bindDouble:forKey: 绑定的值 59 | */ 60 | - (double)lookin_getBindDoubleForKey:(NSString *)key; 61 | 62 | /** 63 | 给对象绑定上一个 BOOL 值以供后续取出使用 64 | */ 65 | - (void)lookin_bindBOOL:(BOOL)boolValue forKey:(NSString *)key; 66 | 67 | /** 68 | 取出之前用 lookin_bindBOOL:forKey: 绑定的值 69 | */ 70 | - (BOOL)lookin_getBindBOOLForKey:(NSString *)key; 71 | 72 | /** 73 | 给对象绑定上一个 long 值以供后续取出使用 74 | */ 75 | - (void)lookin_bindLong:(long)longValue forKey:(NSString *)key; 76 | 77 | /** 78 | 取出之前用 lookin_bindLong:forKey: 绑定的值 79 | */ 80 | - (long)lookin_getBindLongForKey:(NSString *)key; 81 | 82 | /** 83 | 给对象绑定上一个 CGPoint 值以供后续取出使用 84 | */ 85 | - (void)lookin_bindPoint:(CGPoint)pointValue forKey:(NSString *)key; 86 | 87 | /** 88 | 取出之前用 lookin_bindPoint:forKey: 绑定的值 89 | */ 90 | - (CGPoint)lookin_getBindPointForKey:(NSString *)key; 91 | 92 | /** 93 | 移除之前使用 bind 方法绑定的对象 94 | */ 95 | - (void)lookin_clearBindForKey:(NSString *)key; 96 | 97 | @end 98 | 99 | @interface NSObject (Lookin_Coding) 100 | 101 | /// 会把 NSImage/UIImage 转换为 NSData,把 NSColor/UIColor 转换回 NSNumber 数组(rgba) 102 | - (id)lookin_encodedObjectWithType:(LookinCodingValueType)type; 103 | /// 会把 NSData 转换回 NSImage/UIImage,把 NSNumber 数组(rgba) 转换为 NSColor/UIColor 104 | - (id)lookin_decodedObjectWithType:(LookinCodingValueType)type; 105 | 106 | @end 107 | 108 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 109 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/NSSet+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSSet+Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/1/13. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import "TargetConditionals.h" 16 | #if TARGET_OS_IPHONE 17 | #import 18 | #elif TARGET_OS_MAC 19 | #import 20 | #endif 21 | 22 | @interface NSSet<__covariant ValueType> (Lookin) 23 | 24 | - (NSSet *)lookin_map:(id (^)(ValueType obj))block; 25 | 26 | - (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block; 27 | 28 | - (NSSet *)lookin_filter:(BOOL (^)(ValueType obj))block; 29 | 30 | 31 | /** 32 | 是否有任何一个元素满足某条件 33 | @note 元素将被依次传入 block 里,如果任何一个 block 返回 YES,则该方法返回 YES。如果所有 block 均返回 NO,则该方法返回 NO。 34 | */ 35 | - (BOOL)lookin_any:(BOOL (^)(ValueType obj))block; 36 | 37 | @end 38 | 39 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 40 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/NSSet+Lookin.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSSet+Lookin.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/1/13. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "NSSet+Lookin.h" 14 | 15 | @implementation NSSet (Lookin) 16 | 17 | - (NSSet *)lookin_map:(id (^)(id obj))block { 18 | if (!block) { 19 | NSAssert(NO, @""); 20 | return nil; 21 | } 22 | 23 | NSMutableSet *newSet = [NSMutableSet setWithCapacity:self.count]; 24 | [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { 25 | id newObj = block(obj); 26 | if (newObj) { 27 | [newSet addObject:newObj]; 28 | } 29 | }]; 30 | return [newSet copy]; 31 | } 32 | 33 | - (id)lookin_firstFiltered:(BOOL (^)(id obj))block { 34 | if (!block) { 35 | NSAssert(NO, @""); 36 | return nil; 37 | } 38 | 39 | __block id targetObj = nil; 40 | [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { 41 | if (block(obj)) { 42 | targetObj = obj; 43 | *stop = YES; 44 | } 45 | }]; 46 | return targetObj; 47 | } 48 | 49 | - (NSSet *)lookin_filter:(BOOL (^)(id obj))block { 50 | if (!block) { 51 | NSAssert(NO, @""); 52 | return nil; 53 | } 54 | 55 | NSMutableSet *mSet = [NSMutableSet set]; 56 | [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { 57 | if (block(obj)) { 58 | [mSet addObject:obj]; 59 | } 60 | }]; 61 | return [mSet copy]; 62 | } 63 | 64 | - (BOOL)lookin_any:(BOOL (^)(id obj))block { 65 | if (!block) { 66 | NSAssert(NO, @""); 67 | return NO; 68 | } 69 | __block BOOL boolValue = NO; 70 | [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { 71 | if (block(obj)) { 72 | boolValue = YES; 73 | *stop = YES; 74 | } 75 | }]; 76 | return boolValue; 77 | } 78 | 79 | @end 80 | 81 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 82 | -------------------------------------------------------------------------------- /Src/Main/Shared/Category/NSString+Lookin.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // NSString+Lookin.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/5/11. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | 14 | 15 | #import 16 | 17 | @interface NSString (Lookin) 18 | 19 | /** 20 | 把 CGFloat 转成字符串,最多保留 3 位小数,转换后末尾的 0 会被删除 21 | 如:1.2341 => @"1.234", 2.1002 => @"2.1", 3.000 => @"3" 22 | */ 23 | + (NSString *)lookin_stringFromDouble:(double)doubleValue decimal:(NSUInteger)decimal; 24 | 25 | + (NSString *)lookin_stringFromRect:(CGRect)rect; 26 | 27 | + (NSString *)lookin_stringFromInset:(LookinInsets)insets; 28 | 29 | + (NSString *)lookin_stringFromSize:(CGSize)size; 30 | 31 | + (NSString *)lookin_stringFromPoint:(CGPoint)point; 32 | 33 | + (NSString *)lookin_rgbaStringFromColor:(LookinColor *)color; 34 | 35 | - (NSString *)lookin_safeInitWithUTF8String:(const char *)string; 36 | 37 | /// 把 1.2.3 这种 String 版本号转换成数字,可用于大小比较,如 110205 代表 11.2.5 版本 38 | - (NSInteger)lookin_numbericOSVersion; 39 | 40 | @end 41 | 42 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 43 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAppInfo.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAppInfo.h 5 | // qmuidemo 6 | // 7 | // Created by Li Kai on 2018/11/3. 8 | // Copyright © 2018 QMUI Team. All rights reserved. 9 | // 10 | 11 | 12 | 13 | #import "LookinDefines.h" 14 | 15 | typedef NS_ENUM(NSInteger, LookinAppInfoDevice) { 16 | LookinAppInfoDeviceSimulator, // 模拟器 17 | LookinAppInfoDeviceIPad, // iPad 真机 18 | LookinAppInfoDeviceOthers // 应该视为 iPhone 真机 19 | }; 20 | 21 | @interface LookinAppInfo : NSObject 22 | 23 | /// 每次启动 app 时都会随机生成一个 appInfoIdentifier 直到 app 被 kill 掉 24 | @property(nonatomic, assign) NSUInteger appInfoIdentifier; 25 | /// mac 端应该先读取该属性,如果为 YES 则表示应该使用之前保存的旧 appInfo 对象即可 26 | @property(nonatomic, assign) BOOL shouldUseCache; 27 | /// LookinServer 的版本 28 | @property(nonatomic, assign) int serverVersion; 29 | /// 类似 "1.1.9",只在 1.2.3 以及之后的 LookinServer 版本里有值 30 | @property(nonatomic, assign) NSString *serverReadableVersion; 31 | /// 如果 iOS 侧使用了 SPM 或引入了 Swift Subspec,则该属性为 1 32 | /// 如果 iOS 侧没使用,则该属性为 -1 33 | /// 如果不知道,则该属性为 0 34 | @property(nonatomic, assign) int swiftEnabledInLookinServer; 35 | /// app 的当前截图 36 | @property(nonatomic, strong) LookinImage *screenshot; 37 | /// 可能为 nil,比如新建的 iOS 空项目 38 | @property(nonatomic, strong) LookinImage *appIcon; 39 | /// @"微信读书" 40 | @property(nonatomic, copy) NSString *appName; 41 | /// hughkli.lookin 42 | @property(nonatomic, copy) NSString *appBundleIdentifier; 43 | /// @"iPhone X" 44 | @property(nonatomic, copy) NSString *deviceDescription; 45 | /// @"12.1" 46 | @property(nonatomic, copy) NSString *osDescription; 47 | /// 返回 os 的主版本号,比如 iOS 12.1 的设备将返回 12,iOS 13.2.1 的设备将返回 13 48 | @property(nonatomic, assign) NSUInteger osMainVersion; 49 | /// 设备类型 50 | @property(nonatomic, assign) LookinAppInfoDevice deviceType; 51 | /// 屏幕的宽度 52 | @property(nonatomic, assign) double screenWidth; 53 | /// 屏幕的高度 54 | @property(nonatomic, assign) double screenHeight; 55 | /// 是几倍的屏幕 56 | @property(nonatomic, assign) double screenScale; 57 | 58 | - (BOOL)isEqualToAppInfo:(LookinAppInfo *)info; 59 | 60 | #if TARGET_OS_IPHONE 61 | 62 | + (LookinAppInfo *)currentInfoWithScreenshot:(BOOL)hasScreenshot icon:(BOOL)hasIcon localIdentifiers:(NSArray *)localIdentifiers; 63 | 64 | #else 65 | 66 | @property(nonatomic, assign) NSTimeInterval cachedTimestamp; 67 | 68 | #endif 69 | 70 | @end 71 | 72 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 73 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttrType.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttrIdentifiers.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/12/1. 8 | // https://lookin.work 9 | // 10 | 11 | /// 注意:新属性只能加到末尾,否则新旧版本搭配时可能有兼容问题 12 | typedef NS_ENUM(NSInteger, LookinAttrType) { 13 | LookinAttrTypeNone, 14 | LookinAttrTypeVoid, 15 | LookinAttrTypeChar, 16 | LookinAttrTypeInt, 17 | LookinAttrTypeShort, 18 | LookinAttrTypeLong, 19 | LookinAttrTypeLongLong, 20 | LookinAttrTypeUnsignedChar, 21 | LookinAttrTypeUnsignedInt, 22 | LookinAttrTypeUnsignedShort, 23 | LookinAttrTypeUnsignedLong, 24 | LookinAttrTypeUnsignedLongLong, 25 | LookinAttrTypeFloat, 26 | LookinAttrTypeDouble, 27 | LookinAttrTypeBOOL, 28 | LookinAttrTypeSel, 29 | LookinAttrTypeClass, 30 | LookinAttrTypeCGPoint, 31 | LookinAttrTypeCGVector, 32 | LookinAttrTypeCGSize, 33 | LookinAttrTypeCGRect, 34 | LookinAttrTypeCGAffineTransform, 35 | LookinAttrTypeUIEdgeInsets, 36 | LookinAttrTypeUIOffset, 37 | LookinAttrTypeNSString, 38 | LookinAttrTypeEnumInt, 39 | LookinAttrTypeEnumLong, 40 | /// value 实际为 RGBA 数组,即 @[NSNumber, NSNumber, NSNumber, NSNumber],NSNumber 范围是 0 ~ 1 41 | LookinAttrTypeUIColor, 42 | /// 业务需要根据具体的 AttrIdentifier 来解析 43 | LookinAttrTypeCustomObj, 44 | 45 | LookinAttrTypeEnumString, 46 | LookinAttrTypeShadow, 47 | LookinAttrTypeJson 48 | }; 49 | 50 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 51 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttribute.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttribute.h 5 | // qmuidemo 6 | // 7 | // Created by Li Kai on 2018/11/17. 8 | // Copyright © 2018 QMUI Team. All rights reserved. 9 | // 10 | 11 | #import "LookinAttrIdentifiers.h" 12 | #import "LookinCodingValueType.h" 13 | #import "LookinAttrType.h" 14 | 15 | @class LookinDisplayItem; 16 | 17 | @interface LookinAttribute : NSObject 18 | 19 | @property(nonatomic, copy) LookinAttrIdentifier identifier; 20 | 21 | /// 只有 Custom Attr 才有该属性 22 | @property(nonatomic, copy) NSString *displayTitle; 23 | 24 | /// 标识 value 的具体类型(如 double / NSString /...) 25 | @property(nonatomic, assign) LookinAttrType attrType; 26 | 27 | /// 具体的值,需配合 attrType 属性来解析它 28 | /// 对于 String、Color 等 attyType,该属性可能为 nil 29 | @property(nonatomic, strong) id value; 30 | 31 | /// 额外信息,大部分情况下它是 nil 32 | /// 当 attyType 为 LookinAttrTypeEnumString 时,extraValue 是一个 [String] 且保存了 allEnumCases 33 | @property(nonatomic, strong) id extraValue; 34 | 35 | /// 仅 Custom Attr 可能有该属性 36 | /// 对于有 retainedSetter 的 Custom Attr,它的 setter 会以 customSetterID 作为 key 被保存到 LKS_CustomAttrSetterManager 里,后续可以通过这个 uniqueID 重新把 setter 从 LKS_CustomAttrSetterManager 里取出来并调用 37 | @property(nonatomic, copy) NSString *customSetterID; 38 | 39 | #pragma mark - 以下属性不会参与 encode/decode 40 | 41 | /// 标识该 LookinAttribute 对象隶属于哪一个 LookinDisplayItem 42 | @property(nonatomic, weak) LookinDisplayItem *targetDisplayItem; 43 | 44 | - (BOOL)isUserCustom; 45 | 46 | @end 47 | 48 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 49 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttribute.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttribute.m 5 | // qmuidemo 6 | // 7 | // Created by Li Kai on 2018/11/17. 8 | // Copyright © 2018 QMUI Team. All rights reserved. 9 | // 10 | 11 | 12 | 13 | #import "LookinAttribute.h" 14 | #import "LookinDisplayItem.h" 15 | 16 | @implementation LookinAttribute 17 | 18 | #pragma mark - 19 | 20 | - (id)copyWithZone:(NSZone *)zone { 21 | LookinAttribute *newAttr = [[LookinAttribute allocWithZone:zone] init]; 22 | newAttr.identifier = self.identifier; 23 | newAttr.displayTitle = self.displayTitle; 24 | newAttr.value = self.value; 25 | newAttr.attrType = self.attrType; 26 | newAttr.extraValue = self.extraValue; 27 | newAttr.customSetterID = self.customSetterID; 28 | return newAttr; 29 | } 30 | 31 | #pragma mark - 32 | 33 | - (void)encodeWithCoder:(NSCoder *)aCoder { 34 | [aCoder encodeObject:self.displayTitle forKey:@"displayTitle"]; 35 | [aCoder encodeObject:self.identifier forKey:@"identifier"]; 36 | [aCoder encodeInteger:self.attrType forKey:@"attrType"]; 37 | [aCoder encodeObject:self.value forKey:@"value"]; 38 | [aCoder encodeObject:self.extraValue forKey:@"extraValue"]; 39 | [aCoder encodeObject:self.customSetterID forKey:@"customSetterID"]; 40 | } 41 | 42 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 43 | if (self = [super init]) { 44 | self.displayTitle = [aDecoder decodeObjectForKey:@"displayTitle"]; 45 | self.identifier = [aDecoder decodeObjectForKey:@"identifier"]; 46 | self.attrType = [aDecoder decodeIntegerForKey:@"attrType"]; 47 | self.value = [aDecoder decodeObjectForKey:@"value"]; 48 | self.extraValue = [aDecoder decodeObjectForKey:@"extraValue"]; 49 | self.customSetterID = [aDecoder decodeObjectForKey:@"customSetterID"]; 50 | } 51 | return self; 52 | } 53 | 54 | + (BOOL)supportsSecureCoding { 55 | return YES; 56 | } 57 | 58 | - (BOOL)isUserCustom { 59 | return [self.identifier isEqualToString:LookinAttr_UserCustom]; 60 | } 61 | 62 | @end 63 | 64 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 65 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributeModification.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributeModification.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/11/20. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinAttrType.h" 15 | 16 | @interface LookinAttributeModification : NSObject 17 | 18 | @property(nonatomic, assign) unsigned long targetOid; 19 | 20 | @property(nonatomic, assign) SEL setterSelector; 21 | @property(nonatomic, assign) SEL getterSelector; 22 | 23 | @property(nonatomic, assign) LookinAttrType attrType; 24 | @property(nonatomic, strong) id value; 25 | 26 | /// 1.0.4 开始加入这个参数 27 | @property(nonatomic, copy) NSString *clientReadableVersion; 28 | 29 | @end 30 | 31 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 32 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributeModification.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributeModification.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/11/20. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinAttributeModification.h" 12 | 13 | @implementation LookinAttributeModification 14 | 15 | - (void)encodeWithCoder:(NSCoder *)aCoder { 16 | [aCoder encodeObject:@(self.targetOid) forKey:@"targetOid"]; 17 | [aCoder encodeObject:NSStringFromSelector(self.setterSelector) forKey:@"setterSelector"]; 18 | [aCoder encodeInteger:self.attrType forKey:@"attrType"]; 19 | [aCoder encodeObject:self.value forKey:@"value"]; 20 | [aCoder encodeObject:self.clientReadableVersion forKey:@"clientReadableVersion"]; 21 | } 22 | 23 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 24 | if (self = [super init]) { 25 | self.targetOid = [[aDecoder decodeObjectForKey:@"targetOid"] unsignedLongValue]; 26 | self.setterSelector = NSSelectorFromString([aDecoder decodeObjectForKey:@"setterSelector"]); 27 | self.attrType = [aDecoder decodeIntegerForKey:@"attrType"]; 28 | self.value = [aDecoder decodeObjectForKey:@"value"]; 29 | self.clientReadableVersion = [aDecoder decodeObjectForKey:@"clientReadableVersion"]; 30 | } 31 | return self; 32 | } 33 | 34 | + (BOOL)supportsSecureCoding { 35 | return YES; 36 | } 37 | 38 | @end 39 | 40 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 41 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributesGroup.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributesGroup.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/11/19. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinAttrIdentifiers.h" 15 | 16 | @class LookinAttributesSection; 17 | 18 | /** 19 | In Lookin, a LookinAttributesGroup instance will be rendered as a property card. 20 | 21 | When isUserCustom is false: two LookinAttributesGroup instances will be regard as equal when they has the same LookinAttrGroupIdentifier. 22 | When isUserCustom is true: two LookinAttributesGroup instances will be regard as equal when they has the same title. 23 | 当 isUserCustom 为 false 时:若两个 attrGroup 有相同的 LookinAttrGroupIdentifier,则 isEqual: 返回 YES 24 | */ 25 | @interface LookinAttributesGroup : NSObject 26 | 27 | /// 只有在 identifier 为 custom 时,才存在该值 28 | @property(nonatomic, copy) NSString *userCustomTitle; 29 | 30 | @property(nonatomic, copy) LookinAttrGroupIdentifier identifier; 31 | 32 | @property(nonatomic, copy) NSArray *attrSections; 33 | 34 | /// 如果是 custom 则返回 userCustomTitle,如果不是 custom 则返回 identifier 35 | - (NSString *)uniqueKey; 36 | 37 | - (BOOL)isUserCustom; 38 | 39 | @end 40 | 41 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 42 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributesGroup.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributesGroup.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2018/11/19. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinAttributesGroup.h" 14 | #import "LookinAttribute.h" 15 | #import "LookinAttributesSection.h" 16 | #import "LookinDashboardBlueprint.h" 17 | #import "NSArray+Lookin.h" 18 | 19 | @implementation LookinAttributesGroup 20 | 21 | #pragma mark - 22 | 23 | - (id)copyWithZone:(NSZone *)zone { 24 | LookinAttributesGroup *newGroup = [[LookinAttributesGroup allocWithZone:zone] init]; 25 | newGroup.userCustomTitle = self.userCustomTitle; 26 | newGroup.identifier = self.identifier; 27 | newGroup.attrSections = [self.attrSections lookin_map:^id(NSUInteger idx, LookinAttributesSection *value) { 28 | return value.copy; 29 | }]; 30 | return newGroup; 31 | } 32 | 33 | #pragma mark - 34 | 35 | - (void)encodeWithCoder:(NSCoder *)aCoder { 36 | [aCoder encodeObject:self.userCustomTitle forKey:@"userCustomTitle"]; 37 | [aCoder encodeObject:self.identifier forKey:@"identifier"]; 38 | [aCoder encodeObject:self.attrSections forKey:@"attrSections"]; 39 | } 40 | 41 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 42 | if (self = [super init]) { 43 | self.userCustomTitle = [aDecoder decodeObjectForKey:@"userCustomTitle"]; 44 | self.identifier = [aDecoder decodeObjectForKey:@"identifier"]; 45 | self.attrSections = [aDecoder decodeObjectForKey:@"attrSections"]; 46 | } 47 | return self; 48 | } 49 | 50 | - (NSUInteger)hash { 51 | return self.uniqueKey.hash; 52 | } 53 | 54 | - (BOOL)isEqual:(id)object { 55 | if (self == object) { 56 | return YES; 57 | } 58 | if (![object isKindOfClass:[LookinAttributesGroup class]]) { 59 | return NO; 60 | } 61 | LookinAttributesGroup *targetObject = object; 62 | 63 | if (![self.identifier isEqualToString:targetObject.identifier]) { 64 | return false; 65 | } 66 | if ([self.identifier isEqualToString:LookinAttrGroup_UserCustom]) { 67 | BOOL ret = [self.userCustomTitle isEqualToString:targetObject.userCustomTitle]; 68 | return ret; 69 | } else { 70 | return true; 71 | } 72 | } 73 | 74 | + (BOOL)supportsSecureCoding { 75 | return YES; 76 | } 77 | 78 | - (NSString *)uniqueKey { 79 | if ([self.identifier isEqualToString:LookinAttrGroup_UserCustom]) { 80 | return self.userCustomTitle; 81 | } else { 82 | return self.identifier; 83 | } 84 | } 85 | 86 | - (BOOL)isUserCustom { 87 | return [self.identifier isEqualToString:LookinAttrSec_UserCustom]; 88 | } 89 | 90 | @end 91 | 92 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 93 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributesSection.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributesSection.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/3/2. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinAttrIdentifiers.h" 15 | 16 | @class LookinAttribute; 17 | 18 | typedef NS_ENUM (NSInteger, LookinAttributesSectionStyle) { 19 | LookinAttributesSectionStyleDefault, // 每个 attr 独占一行 20 | LookinAttributesSectionStyle0, // frame 等卡片使用,前 4 个 attr 每行两个,之后每个 attr 在同一排,每个宽度为 1/4 21 | LookinAttributesSectionStyle1, // 第一个 attr 在第一排靠左,第二个 attr 在第一排靠右,之后的 attr 每个独占一行 22 | LookinAttributesSectionStyle2 // 第一排独占一行,剩下的在同一行且均分宽度 23 | }; 24 | 25 | @interface LookinAttributesSection : NSObject 26 | 27 | @property(nonatomic, copy) LookinAttrSectionIdentifier identifier; 28 | 29 | @property(nonatomic, copy) NSArray *attributes; 30 | 31 | - (BOOL)isUserCustom; 32 | 33 | @end 34 | 35 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 36 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAttributesSection.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAttributesSection.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/3/2. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinAttributesSection.h" 14 | #import "LookinAttribute.h" 15 | 16 | #import "NSArray+Lookin.h" 17 | 18 | @implementation LookinAttributesSection 19 | 20 | #pragma mark - 21 | 22 | - (id)copyWithZone:(NSZone *)zone { 23 | LookinAttributesSection *newSection = [[LookinAttributesSection allocWithZone:zone] init]; 24 | newSection.identifier = self.identifier; 25 | newSection.attributes = [self.attributes lookin_map:^id(NSUInteger idx, LookinAttribute *value) { 26 | return value.copy; 27 | }]; 28 | return newSection; 29 | } 30 | 31 | #pragma mark - 32 | 33 | - (void)encodeWithCoder:(NSCoder *)aCoder { 34 | [aCoder encodeObject:self.identifier forKey:@"identifier"]; 35 | [aCoder encodeObject:self.attributes forKey:@"attributes"]; 36 | } 37 | 38 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 39 | if (self = [super init]) { 40 | self.identifier = [aDecoder decodeObjectForKey:@"identifier"]; 41 | self.attributes = [aDecoder decodeObjectForKey:@"attributes"]; 42 | } 43 | return self; 44 | } 45 | 46 | + (BOOL)supportsSecureCoding { 47 | return YES; 48 | } 49 | 50 | - (BOOL)isUserCustom { 51 | return [self.identifier isEqualToString:LookinAttrSec_UserCustom]; 52 | } 53 | 54 | @end 55 | 56 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 57 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinAutoLayoutConstraint.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinAutoLayoutConstraint.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/9/28. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinDefines.h" 14 | 15 | @class LookinObject; 16 | 17 | typedef NS_ENUM(NSInteger, LookinConstraintItemType) { 18 | LookinConstraintItemTypeUnknown, 19 | LookinConstraintItemTypeNil, 20 | LookinConstraintItemTypeView, 21 | LookinConstraintItemTypeSelf, 22 | LookinConstraintItemTypeSuper, 23 | LookinConstraintItemTypeLayoutGuide 24 | }; 25 | 26 | @interface LookinAutoLayoutConstraint : NSObject 27 | 28 | #if TARGET_OS_IPHONE 29 | + (instancetype)instanceFromNSConstraint:(NSLayoutConstraint *)constraint isEffective:(BOOL)isEffective firstItemType:(LookinConstraintItemType)firstItemType secondItemType:(LookinConstraintItemType)secondItemType; 30 | #endif 31 | 32 | @property(nonatomic, assign) BOOL effective; 33 | @property(nonatomic, assign) BOOL active; 34 | @property(nonatomic, assign) BOOL shouldBeArchived; 35 | @property(nonatomic, strong) LookinObject *firstItem; 36 | @property(nonatomic, assign) LookinConstraintItemType firstItemType; 37 | /// iOS 里的 NSLayoutAttribute,注意 iOS 和 macOS 虽然都有 NSLayoutAttribute 但是 value 非常不同,因此这里使用 NSInteger 避免混淆 38 | @property(nonatomic, assign) NSInteger firstAttribute; 39 | @property(nonatomic, assign) NSLayoutRelation relation; 40 | @property(nonatomic, strong) LookinObject *secondItem; 41 | @property(nonatomic, assign) LookinConstraintItemType secondItemType; 42 | /// iOS 里的 NSLayoutAttribute,注意 iOS 和 macOS 虽然都有 NSLayoutAttribute 但是 value 非常不同,因此这里使用 NSInteger 避免混淆 43 | @property(nonatomic, assign) NSInteger secondAttribute; 44 | @property(nonatomic, assign) CGFloat multiplier; 45 | @property(nonatomic, assign) CGFloat constant; 46 | @property(nonatomic, assign) CGFloat priority; 47 | @property(nonatomic, copy) NSString *identifier; 48 | 49 | @end 50 | 51 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 52 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinCodingValueType.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinCodingValueType.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/2/13. 8 | // https://lookin.work 9 | // 10 | 11 | typedef NS_ENUM(NSInteger, LookinCodingValueType) { 12 | LookinCodingValueTypeUnknown, 13 | LookinCodingValueTypeChar, 14 | LookinCodingValueTypeDouble, 15 | LookinCodingValueTypeFloat, 16 | LookinCodingValueTypeLongLong, 17 | // LookinCodingValueTypePoint, 18 | // LookinCodingValueTypeString, 19 | // LookinCodingValueTypeStringArray, 20 | // LookinCodingValueTypeEdgeInsets, 21 | // LookinCodingValueTypeRect, 22 | LookinCodingValueTypeBOOL, 23 | // LookinCodingValueTypeSize, 24 | LookinCodingValueTypeColor, 25 | LookinCodingValueTypeEnum, 26 | // LookinCodingValueTypeRange, 27 | LookinCodingValueTypeImage 28 | }; 29 | 30 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 31 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinConnectionAttachment.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinConnectionAttachment.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/2/15. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinCodingValueType.h" 15 | 16 | @interface LookinConnectionAttachment : NSObject 17 | 18 | @property(nonatomic, assign) LookinCodingValueType dataType; 19 | 20 | @property(nonatomic, strong) id data; 21 | 22 | @end 23 | 24 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 25 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinConnectionAttachment.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinConnectionAttachment.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/2/15. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinConnectionAttachment.h" 14 | #import "LookinDefines.h" 15 | #import "NSObject+Lookin.h" 16 | 17 | static NSString * const Key_Data = @"0"; 18 | static NSString * const Key_DataType = @"1"; 19 | 20 | @interface LookinConnectionAttachment () 21 | 22 | @end 23 | 24 | @implementation LookinConnectionAttachment 25 | 26 | - (instancetype)init { 27 | if (self = [super init]) { 28 | } 29 | return self; 30 | } 31 | 32 | - (void)encodeWithCoder:(NSCoder *)aCoder { 33 | 34 | [aCoder encodeObject:[self.data lookin_encodedObjectWithType:self.dataType] forKey:Key_Data]; 35 | [aCoder encodeInteger:self.dataType forKey:Key_DataType]; 36 | } 37 | 38 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 39 | if (self = [super init]) { 40 | self.dataType = [aDecoder decodeIntegerForKey:Key_DataType]; 41 | self.data = [[aDecoder decodeObjectForKey:Key_Data] lookin_decodedObjectWithType:self.dataType]; 42 | } 43 | return self; 44 | } 45 | 46 | + (BOOL)supportsSecureCoding { 47 | return YES; 48 | } 49 | 50 | @end 51 | 52 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 53 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinConnectionResponseAttachment.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinConnectionResponse.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/1/15. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinConnectionAttachment.h" 15 | 16 | @interface LookinConnectionResponseAttachment : LookinConnectionAttachment 17 | 18 | + (instancetype)attachmentWithError:(NSError *)error; 19 | 20 | @property(nonatomic, assign) int lookinServerVersion; 21 | 22 | @property(nonatomic, strong) NSError *error; 23 | 24 | /// 如果为 YES,则表示 app 正处于后台模式,默认为 NO 25 | @property(nonatomic, assign) BOOL appIsInBackground; 26 | 27 | /** 28 | dataTotalCount 为 0 时表示仅有这一个 response,默认为 0 29 | dataTotalCount 大于 0 时表示可能有多个 response,当所有 response 的 currentDataCount 的总和大于 dataTotalCount 即表示所有 response 已接收完毕 30 | */ 31 | @property(nonatomic, assign) NSUInteger dataTotalCount; 32 | @property(nonatomic, assign) NSUInteger currentDataCount; 33 | 34 | @end 35 | 36 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 37 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinConnectionResponseAttachment.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinConnectionResponse.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/1/15. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinConnectionResponseAttachment.h" 14 | #import "LookinDefines.h" 15 | 16 | @interface LookinConnectionResponseAttachment () 17 | 18 | @end 19 | 20 | @implementation LookinConnectionResponseAttachment 21 | 22 | - (void)encodeWithCoder:(NSCoder *)aCoder { 23 | [super encodeWithCoder:aCoder]; 24 | [aCoder encodeInt:self.lookinServerVersion forKey:@"lookinServerVersion"]; 25 | [aCoder encodeObject:self.error forKey:@"error"]; 26 | [aCoder encodeObject:@(self.dataTotalCount) forKey:@"dataTotalCount"]; 27 | [aCoder encodeObject:@(self.currentDataCount) forKey:@"currentDataCount"]; 28 | [aCoder encodeBool:self.appIsInBackground forKey:@"appIsInBackground"]; 29 | } 30 | 31 | - (instancetype)init { 32 | if (self = [super init]) { 33 | self.lookinServerVersion = LOOKIN_SERVER_VERSION; 34 | self.dataTotalCount = 0; 35 | } 36 | return self; 37 | } 38 | 39 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 40 | if (self = [super initWithCoder:aDecoder]) { 41 | self.lookinServerVersion = [aDecoder decodeIntForKey:@"lookinServerVersion"]; 42 | self.error = [aDecoder decodeObjectForKey:@"error"]; 43 | self.dataTotalCount = [[aDecoder decodeObjectForKey:@"dataTotalCount"] unsignedIntegerValue]; 44 | self.currentDataCount = [[aDecoder decodeObjectForKey:@"currentDataCount"] unsignedIntegerValue]; 45 | self.appIsInBackground = [aDecoder decodeBoolForKey:@"appIsInBackground"]; 46 | } 47 | return self; 48 | } 49 | 50 | + (BOOL)supportsSecureCoding { 51 | return YES; 52 | } 53 | 54 | + (instancetype)attachmentWithError:(NSError *)error { 55 | LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new]; 56 | attachment.error = error; 57 | return attachment; 58 | } 59 | 60 | @end 61 | 62 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 63 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinCustomAttrModification.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LookinCustomAttrModification.h 4 | // LookinShared 5 | // 6 | // Created by likaimacbookhome on 2023/11/4. 7 | // 8 | 9 | #import 10 | #import "LookinAttrType.h" 11 | 12 | @interface LookinCustomAttrModification : NSObject 13 | 14 | @property(nonatomic, assign) LookinAttrType attrType; 15 | @property(nonatomic, copy) NSString *customSetterID; 16 | @property(nonatomic, strong) id value; 17 | 18 | @end 19 | 20 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 21 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinCustomAttrModification.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LookinCustomAttrModification.m 4 | // LookinShared 5 | // 6 | // Created by likaimacbookhome on 2023/11/4. 7 | // 8 | 9 | #import "LookinCustomAttrModification.h" 10 | 11 | @implementation LookinCustomAttrModification 12 | 13 | - (void)encodeWithCoder:(NSCoder *)aCoder { 14 | [aCoder encodeInteger:self.attrType forKey:@"attrType"]; 15 | [aCoder encodeObject:self.value forKey:@"value"]; 16 | [aCoder encodeObject:self.customSetterID forKey:@"customSetterID"]; 17 | } 18 | 19 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 20 | if (self = [super init]) { 21 | self.attrType = [aDecoder decodeIntegerForKey:@"attrType"]; 22 | self.value = [aDecoder decodeObjectForKey:@"value"]; 23 | self.customSetterID = [aDecoder decodeObjectForKey:@"customSetterID"]; 24 | } 25 | return self; 26 | } 27 | 28 | + (BOOL)supportsSecureCoding { 29 | return YES; 30 | } 31 | 32 | @end 33 | 34 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 35 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinCustomDisplayItemInfo.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | // 3 | // LookinCustomDisplayItemInfo.h 4 | // LookinServer 5 | // 6 | // Created by likai.123 on 2023/11/1. 7 | // 8 | 9 | #import 10 | 11 | @interface LookinCustomDisplayItemInfo : NSObject 12 | 13 | /// 该属性可能有值(CGRect)也可能是 nil(nil 时则表示无图像) 14 | @property(nonatomic, strong) NSValue *frameInWindow; 15 | @property(nonatomic, copy) NSString *title; 16 | @property(nonatomic, copy) NSString *subtitle; 17 | @property(nonatomic, copy) NSString *danceuiSource; 18 | 19 | @end 20 | 21 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 22 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinCustomDisplayItemInfo.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinCustomDisplayItemInfo.m 5 | // LookinServer 6 | // 7 | // Created by likai.123 on 2023/11/1. 8 | // 9 | 10 | #import "LookinCustomDisplayItemInfo.h" 11 | #if TARGET_OS_IPHONE 12 | #import 13 | #endif 14 | 15 | @implementation LookinCustomDisplayItemInfo 16 | 17 | - (id)copyWithZone:(NSZone *)zone { 18 | LookinCustomDisplayItemInfo *newInstance = [[LookinCustomDisplayItemInfo allocWithZone:zone] init]; 19 | 20 | if (self.frameInWindow) { 21 | #if TARGET_OS_IPHONE 22 | CGRect rect = [self.frameInWindow CGRectValue]; 23 | newInstance.frameInWindow = [NSValue valueWithCGRect:rect]; 24 | #elif TARGET_OS_MAC 25 | CGRect rect = [self.frameInWindow rectValue]; 26 | newInstance.frameInWindow = [NSValue valueWithRect:rect]; 27 | #endif 28 | } 29 | newInstance.title = self.title; 30 | newInstance.subtitle = self.subtitle; 31 | newInstance.danceuiSource = self.danceuiSource; 32 | 33 | return newInstance; 34 | } 35 | 36 | - (void)encodeWithCoder:(NSCoder *)aCoder { 37 | [aCoder encodeObject:self.frameInWindow forKey:@"frameInWindow"]; 38 | [aCoder encodeObject:self.title forKey:@"title"]; 39 | [aCoder encodeObject:self.subtitle forKey:@"subtitle"]; 40 | [aCoder encodeObject:self.danceuiSource forKey:@"danceuiSource"]; 41 | } 42 | 43 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 44 | if (self = [super init]) { 45 | self.frameInWindow = [aDecoder decodeObjectForKey:@"frameInWindow"]; 46 | self.title = [aDecoder decodeObjectForKey:@"title"]; 47 | self.subtitle = [aDecoder decodeObjectForKey:@"subtitle"]; 48 | self.danceuiSource = [aDecoder decodeObjectForKey:@"danceuiSource"]; 49 | } 50 | return self; 51 | } 52 | 53 | + (BOOL)supportsSecureCoding { 54 | return YES; 55 | } 56 | 57 | @end 58 | 59 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 60 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinDashboardBlueprint.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinDashboardBlueprint.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/6/5. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | #import "LookinAttrIdentifiers.h" 15 | #import "LookinAttrType.h" 16 | 17 | /** 18 | 该对象定义了: 19 | - 每一个 Attr 的信息 20 | - 哪些 GroupID, SectionID, AttrID 是合法的 21 | - 这些 ID 的父子顺序,比如 LookinAttrGroup_Frame 包含哪些 Section 22 | - 这些 ID 展示顺序(比如哪个 Group 在前、哪个 Group 在后) 23 | */ 24 | @interface LookinDashboardBlueprint : NSObject 25 | 26 | + (NSArray *)groupIDs; 27 | 28 | + (NSArray *)sectionIDsForGroupID:(LookinAttrGroupIdentifier)groupID; 29 | 30 | + (NSArray *)attrIDsForSectionID:(LookinAttrSectionIdentifier)sectionID; 31 | 32 | /// 返回包含目标 attr 的 groupID 和 sectionID 33 | + (void)getHostGroupID:(inout LookinAttrGroupIdentifier *)groupID sectionID:(inout LookinAttrSectionIdentifier *)sectionID fromAttrID:(LookinAttrIdentifier)attrID; 34 | 35 | /// 返回某个 group 的标题 36 | + (NSString *)groupTitleWithGroupID:(LookinAttrGroupIdentifier)groupID; 37 | 38 | /// 返回某个 section 的标题,nil 则表示不显示标题 39 | + (NSString *)sectionTitleWithSectionID:(LookinAttrSectionIdentifier)secID; 40 | 41 | /// 当某个 LookinAttribute 确定是 NSObject 类型时,该方法返回它具体是什么对象,比如 UIColor 等 42 | + (LookinAttrType)objectAttrTypeWithAttrID:(LookinAttrIdentifier)attrID; 43 | 44 | /// 返回某个 LookinAttribute 代表的属性是哪一个类拥有的,比如 LookinAttrSec_UILabel_TextColor 是 UILabel 才有的 45 | + (NSString *)classNameWithAttrID:(LookinAttrIdentifier)attrID; 46 | 47 | /// 一个 attr 要么属于 UIView 要么属于 CALayer,如果它属于 UIView 那么该方法返回 YES 48 | + (BOOL)isUIViewPropertyWithAttrID:(LookinAttrIdentifier)attrID; 49 | 50 | /// 如果某个 attribute 是 enum,则这里会返回相应的 enum 的名称(如 @"NSTextAlignment"),进而可通过这个名称查询可用的枚举值列表 51 | + (NSString *)enumListNameWithAttrID:(LookinAttrIdentifier)attrID; 52 | 53 | /// 如果返回 YES,则说明用户在 Lookin 里修改了该 Attribute 的值后,应该重新拉取和更新相关图层的位置、截图等信息 54 | + (BOOL)needPatchAfterModificationWithAttrID:(LookinAttrIdentifier)attrID; 55 | 56 | /// 完整的名字 57 | + (NSString *)fullTitleWithAttrID:(LookinAttrIdentifier)attrID; 58 | 59 | /// 在某些 textField 和 checkbox 里会显示这里返回的 title 60 | + (NSString *)briefTitleWithAttrID:(LookinAttrIdentifier)attrID; 61 | 62 | /// 获取 getter 方法 63 | + (SEL)getterWithAttrID:(LookinAttrIdentifier)attrID; 64 | 65 | /// 获取 setter 方法 66 | + (SEL)setterWithAttrID:(LookinAttrIdentifier)attrID; 67 | 68 | /// 获取 “hideIfNil” 的值。如果为 YES,则当读取 getter 获取的 value 为 nil 时,Lookin 不会传输该 attr 69 | /// 如果为 NO,则即使 value 为 nil 也会传输(比如 label 的 text 属性,即使它是 nil 我们也要显示,所以它的 hideIfNil 应该为 NO) 70 | + (BOOL)hideIfNilWithAttrID:(LookinAttrIdentifier)attrID; 71 | 72 | /// 该属性需要的最低的 iOS 版本,比如 safeAreaInsets 从 iOS 11.0 开始出现,则该方法返回 11,如果返回 0 则表示不限制 iOS 版本(注意 Lookin 项目仅支持 iOS 8.0+) 73 | + (NSInteger)minAvailableOSVersionWithAttrID:(LookinAttrIdentifier)attrID; 74 | 75 | @end 76 | 77 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 78 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinDisplayItemDetail.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinDisplayItemDetail.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/2/19. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDefines.h" 12 | 13 | @class LookinAttributesGroup; 14 | @class LookinDisplayItem; 15 | 16 | @interface LookinDisplayItemDetail : NSObject 17 | 18 | @property(nonatomic, assign) unsigned long displayItemOid; 19 | 20 | @property(nonatomic, strong) LookinImage *groupScreenshot; 21 | 22 | @property(nonatomic, strong) LookinImage *soloScreenshot; 23 | 24 | @property(nonatomic, strong) NSValue *frameValue; 25 | 26 | @property(nonatomic, strong) NSValue *boundsValue; 27 | 28 | @property(nonatomic, strong) NSNumber *hiddenValue; 29 | 30 | @property(nonatomic, strong) NSNumber *alphaValue; 31 | 32 | @property(nonatomic, copy) NSString *customDisplayTitle; 33 | 34 | @property(nonatomic, copy) NSString *danceUISource; 35 | 36 | @property(nonatomic, copy) NSArray *attributesGroupList; 37 | @property(nonatomic, copy) NSArray *customAttrGroupList; 38 | 39 | /// 注意 nil 和空数组的区别:nil 表示该属性无意义,空数组表示 subviews 为空 40 | /// Client 1.0.7 & Server 1.2.7 开始支持该属性 41 | /// 默认为 nil 42 | @property(nonatomic, copy) NSArray *subitems; 43 | 44 | /// 当 Server 找不到 task 对应的图层时,会返回一个特殊的 LookinDisplayItemDetail 对象,这个对象会被设置 displayItemOid 和 failureCode,其中 failureCode 会被置为 -1 45 | /// Client 1.0.7 & Server 1.2.7 开始支持该属性 46 | /// 默认为 0 47 | @property(nonatomic, assign) NSInteger failureCode; 48 | 49 | @end 50 | 51 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 52 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinDisplayItemDetail.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinDisplayItemDetail.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/2/19. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinDisplayItemDetail.h" 12 | #import "Image+Lookin.h" 13 | 14 | #if TARGET_OS_IPHONE 15 | #import "UIImage+LookinServer.h" 16 | #endif 17 | 18 | @implementation LookinDisplayItemDetail 19 | 20 | - (void)encodeWithCoder:(NSCoder *)aCoder { 21 | [aCoder encodeObject:@(self.displayItemOid) forKey:@"displayItemOid"]; 22 | [aCoder encodeObject:self.groupScreenshot.lookin_data forKey:@"groupScreenshot"]; 23 | [aCoder encodeObject:self.soloScreenshot.lookin_data forKey:@"soloScreenshot"]; 24 | [aCoder encodeObject:self.frameValue forKey:@"frameValue"]; 25 | [aCoder encodeObject:self.boundsValue forKey:@"boundsValue"]; 26 | [aCoder encodeObject:self.hiddenValue forKey:@"hiddenValue"]; 27 | [aCoder encodeObject:self.alphaValue forKey:@"alphaValue"]; 28 | [aCoder encodeObject:self.attributesGroupList forKey:@"attributesGroupList"]; 29 | [aCoder encodeObject:self.customAttrGroupList forKey:@"customAttrGroupList"]; 30 | [aCoder encodeObject:self.customDisplayTitle forKey:@"customDisplayTitle"]; 31 | [aCoder encodeObject:self.danceUISource forKey:@"danceUISource"]; 32 | [aCoder encodeInteger:self.failureCode forKey:@"failureCode"]; 33 | if (self.subitems) { 34 | [aCoder encodeObject:self.subitems forKey:@"subitems"]; 35 | } 36 | } 37 | 38 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 39 | if (self = [super init]) { 40 | self.displayItemOid = [[aDecoder decodeObjectForKey:@"displayItemOid"] unsignedLongValue]; 41 | self.groupScreenshot = [[LookinImage alloc] initWithData:[aDecoder decodeObjectForKey:@"groupScreenshot"]]; 42 | self.soloScreenshot = [[LookinImage alloc] initWithData:[aDecoder decodeObjectForKey:@"soloScreenshot"]]; 43 | self.frameValue = [aDecoder decodeObjectForKey:@"frameValue"]; 44 | self.boundsValue = [aDecoder decodeObjectForKey:@"boundsValue"]; 45 | self.hiddenValue = [aDecoder decodeObjectForKey:@"hiddenValue"]; 46 | self.alphaValue = [aDecoder decodeObjectForKey:@"alphaValue"]; 47 | self.attributesGroupList = [aDecoder decodeObjectForKey:@"attributesGroupList"]; 48 | self.customAttrGroupList = [aDecoder decodeObjectForKey:@"customAttrGroupList"]; 49 | self.customDisplayTitle = [aDecoder decodeObjectForKey:@"customDisplayTitle"]; 50 | self.danceUISource = [aDecoder decodeObjectForKey:@"danceUISource"]; 51 | 52 | if ([aDecoder containsValueForKey:@"failureCode"]) { 53 | self.failureCode = [aDecoder decodeIntegerForKey:@"failureCode"]; 54 | } else { 55 | self.failureCode = 0; 56 | } 57 | 58 | if ([aDecoder containsValueForKey:@"subitems"]) { 59 | self.subitems = [aDecoder decodeObjectForKey:@"subitems"]; 60 | } 61 | } 62 | return self; 63 | } 64 | 65 | + (BOOL)supportsSecureCoding { 66 | return YES; 67 | } 68 | 69 | @end 70 | 71 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 72 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinEventHandler.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinEventHandler.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/7. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @class LookinObject, LookinIvarTrace, LookinStringTwoTuple; 16 | 17 | typedef NS_ENUM(NSInteger, LookinEventHandlerType) { 18 | LookinEventHandlerTypeTargetAction, 19 | LookinEventHandlerTypeGesture 20 | }; 21 | 22 | @interface LookinEventHandler : NSObject 23 | 24 | @property(nonatomic, assign) LookinEventHandlerType handlerType; 25 | 26 | /// 比如 "UIControlEventTouchUpInside", "UITapGestureRecognizer" 27 | @property(nonatomic, copy) NSString *eventName; 28 | /// tuple.first => @"",tuple.second => @"handleTap" 29 | @property(nonatomic, copy) NSArray *targetActions; 30 | 31 | /// 返回当前 recognizer 是继承自哪一个基本款 recognizer。 32 | /// 基本款 recognizer 指的是 TapRecognizer, PinchRecognizer 之类的常见 recognizer 33 | /// 如果当前 recognizer 本身就是基本款 recognizer,则该属性为 nil 34 | @property(nonatomic, copy) NSString *inheritedRecognizerName; 35 | @property(nonatomic, assign) BOOL gestureRecognizerIsEnabled; 36 | @property(nonatomic, copy) NSString *gestureRecognizerDelegator; 37 | @property(nonatomic, copy) NSArray *recognizerIvarTraces; 38 | /// recognizer 对象 39 | @property(nonatomic, assign) unsigned long long recognizerOid; 40 | 41 | @end 42 | 43 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 44 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinEventHandler.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinEventHandler.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/7. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinEventHandler.h" 14 | #import "LookinObject.h" 15 | #import "LookinTuple.h" 16 | 17 | #import "NSArray+Lookin.h" 18 | 19 | @implementation LookinEventHandler 20 | 21 | #pragma mark - 22 | 23 | - (id)copyWithZone:(NSZone *)zone { 24 | LookinEventHandler *newHandler = [[LookinEventHandler allocWithZone:zone] init]; 25 | newHandler.handlerType = self.handlerType; 26 | newHandler.eventName = self.eventName; 27 | newHandler.targetActions = [self.targetActions lookin_map:^id(NSUInteger idx, LookinStringTwoTuple *value) { 28 | return value.copy; 29 | }]; 30 | newHandler.gestureRecognizerIsEnabled = self.gestureRecognizerIsEnabled; 31 | newHandler.gestureRecognizerDelegator = self.gestureRecognizerDelegator; 32 | newHandler.inheritedRecognizerName = self.inheritedRecognizerName; 33 | newHandler.recognizerIvarTraces = self.recognizerIvarTraces.copy; 34 | newHandler.recognizerOid = self.recognizerOid; 35 | return newHandler; 36 | } 37 | 38 | #pragma mark - 39 | 40 | - (void)encodeWithCoder:(NSCoder *)aCoder { 41 | [aCoder encodeInteger:self.handlerType forKey:@"handlerType"]; 42 | [aCoder encodeBool:self.gestureRecognizerIsEnabled forKey:@"gestureRecognizerIsEnabled"]; 43 | [aCoder encodeObject:self.eventName forKey:@"eventName"]; 44 | [aCoder encodeObject:self.gestureRecognizerDelegator forKey:@"gestureRecognizerDelegator"]; 45 | [aCoder encodeObject:self.targetActions forKey:@"targetActions"]; 46 | [aCoder encodeObject:self.inheritedRecognizerName forKey:@"inheritedRecognizerName"]; 47 | [aCoder encodeObject:self.recognizerIvarTraces forKey:@"recognizerIvarTraces"]; 48 | [aCoder encodeObject:@(self.recognizerOid) forKey:@"recognizerOid"]; 49 | } 50 | 51 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 52 | if (self = [super init]) { 53 | self.handlerType = [aDecoder decodeIntegerForKey:@"handlerType"]; 54 | self.gestureRecognizerIsEnabled = [aDecoder decodeBoolForKey:@"gestureRecognizerIsEnabled"]; 55 | self.eventName = [aDecoder decodeObjectForKey:@"eventName"]; 56 | self.gestureRecognizerDelegator = [aDecoder decodeObjectForKey:@"gestureRecognizerDelegator"]; 57 | self.targetActions = [aDecoder decodeObjectForKey:@"targetActions"]; 58 | self.inheritedRecognizerName = [aDecoder decodeObjectForKey:@"inheritedRecognizerName"]; 59 | self.recognizerIvarTraces = [aDecoder decodeObjectForKey:@"recognizerIvarTraces"]; 60 | self.recognizerOid = ((NSNumber *)[aDecoder decodeObjectForKey:@"recognizerOid"]).unsignedLongValue; 61 | } 62 | return self; 63 | } 64 | 65 | + (BOOL)supportsSecureCoding { 66 | return YES; 67 | } 68 | 69 | @end 70 | 71 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 72 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinHierarchyFile.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinHierarchyFile.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/5/12. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @class LookinHierarchyInfo; 16 | 17 | @interface LookinHierarchyFile : NSObject 18 | 19 | /// 记录创建该文件的 LookinServer 的版本 20 | @property(nonatomic, assign) int serverVersion; 21 | 22 | @property(nonatomic, strong) LookinHierarchyInfo *hierarchyInfo; 23 | 24 | @property(nonatomic, copy) NSDictionary *soloScreenshots; 25 | @property(nonatomic, copy) NSDictionary *groupScreenshots; 26 | 27 | /// 验证 file 的版本之类的是否和当前 Lookin 客户端匹配,如果没有问题则返回 nil,如果有问题则返回 error 28 | + (NSError *)verifyHierarchyFile:(LookinHierarchyFile *)file; 29 | 30 | @end 31 | 32 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 33 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinHierarchyFile.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinHierarchyFile.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/5/12. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinHierarchyFile.h" 14 | 15 | #import "NSArray+Lookin.h" 16 | 17 | @implementation LookinHierarchyFile 18 | 19 | - (void)encodeWithCoder:(NSCoder *)aCoder { 20 | [aCoder encodeInt:self.serverVersion forKey:@"serverVersion"]; 21 | [aCoder encodeObject:self.hierarchyInfo forKey:@"hierarchyInfo"]; 22 | [aCoder encodeObject:self.soloScreenshots forKey:@"soloScreenshots"]; 23 | [aCoder encodeObject:self.groupScreenshots forKey:@"groupScreenshots"]; 24 | } 25 | 26 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 27 | if (self = [super init]) { 28 | self.serverVersion = [aDecoder decodeIntForKey:@"serverVersion"]; 29 | self.hierarchyInfo = [aDecoder decodeObjectForKey:@"hierarchyInfo"]; 30 | self.soloScreenshots = [aDecoder decodeObjectForKey:@"soloScreenshots"]; 31 | self.groupScreenshots = [aDecoder decodeObjectForKey:@"groupScreenshots"]; 32 | } 33 | return self; 34 | } 35 | 36 | + (BOOL)supportsSecureCoding { 37 | return YES; 38 | } 39 | 40 | + (NSError *)verifyHierarchyFile:(LookinHierarchyFile *)hierarchyFile { 41 | if (![hierarchyFile isKindOfClass:[LookinHierarchyFile class]]) { 42 | return LookinErr_Inner; 43 | } 44 | 45 | if (hierarchyFile.serverVersion < LOOKIN_SUPPORTED_SERVER_MIN) { 46 | // 文件版本太旧 47 | // 如果不存在 serverVersion 这个字段,说明版本是 6 48 | int fileVersion = hierarchyFile.serverVersion ? : 6; 49 | NSString *detail = [NSString stringWithFormat:NSLocalizedString(@"The document was created by a Lookin app with too old version. Current Lookin app version is %@, but the document version is %@.", nil), @(LOOKIN_CLIENT_VERSION), @(fileVersion)]; 50 | return [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_ServerVersionTooLow userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"Failed to open the document.", nil), NSLocalizedRecoverySuggestionErrorKey:detail}]; 51 | } 52 | 53 | if (hierarchyFile.serverVersion > LOOKIN_SUPPORTED_SERVER_MAX) { 54 | // 文件版本太新 55 | NSString *detail = [NSString stringWithFormat:NSLocalizedString(@"Current Lookin app is too old to open this document. Current Lookin app version is %@, but the document version is %@.", nil), @(LOOKIN_CLIENT_VERSION), @(hierarchyFile.serverVersion)]; 56 | return [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_ServerVersionTooHigh userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"Failed to open the document.", nil), NSLocalizedRecoverySuggestionErrorKey:detail}]; 57 | } 58 | 59 | return nil; 60 | } 61 | 62 | @end 63 | 64 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 65 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinHierarchyInfo.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinDisplayInfo.h 5 | // WeRead 6 | // 7 | // Created by Li Kai on 2018/10/22. 8 | // Copyright © 2018年 tencent. All rights reserved. 9 | // 10 | 11 | 12 | 13 | #import "LookinDefines.h" 14 | #import "TargetConditionals.h" 15 | #if TARGET_OS_IPHONE 16 | #import 17 | #elif TARGET_OS_MAC 18 | #import 19 | #endif 20 | 21 | @class LookinDisplayItem, LookinAttributesGroup, LookinAppInfo; 22 | 23 | @interface LookinHierarchyInfo : NSObject 24 | 25 | #if TARGET_OS_IPHONE 26 | 27 | /// version 可能为 nil,此时说明 Client 版本号 < 1.0.4 28 | + (instancetype)staticInfoWithLookinVersion:(NSString *)version; 29 | 30 | + (instancetype)exportedInfo; 31 | 32 | #endif 33 | 34 | /// 这里其实就是顶端的那几个 UIWindow 35 | @property(nonatomic, copy) NSArray *displayItems; 36 | 37 | @property(nonatomic, copy) NSDictionary *colorAlias; 38 | 39 | @property(nonatomic, copy) NSArray *collapsedClassList; 40 | 41 | @property(nonatomic, strong) LookinAppInfo *appInfo; 42 | 43 | @property(nonatomic, assign) int serverVersion; 44 | 45 | @end 46 | 47 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 48 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinObject.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinObject.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/4/20. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @class LookinObjectIvar, LookinIvarTrace; 16 | 17 | @interface LookinObject : NSObject 18 | 19 | #if TARGET_OS_IPHONE 20 | + (instancetype)instanceWithObject:(NSObject *)object; 21 | #endif 22 | 23 | @property(nonatomic, assign) unsigned long oid; 24 | 25 | @property(nonatomic, copy) NSString *memoryAddress; 26 | 27 | /** 28 | 比如有一个 UILabel 对象,则它的 classChainList 为 @[@"UILabel", @"UIView", @"UIResponder", @"NSObject"],而它的 ivarList 长度为 4,idx 从小到大分别是 UILabel 层级的 ivars, UIView 层级的 ivars..... 29 | */ 30 | @property(nonatomic, copy) NSArray *classChainList; 31 | 32 | @property(nonatomic, copy) NSString *specialTrace; 33 | 34 | @property(nonatomic, copy) NSArray *ivarTraces; 35 | 36 | /// 没有 demangle,会包含 Swift Module Name 37 | /// 在 Lookin 的展示中,绝大多数情况下应该使用 lk_demangledSwiftName 38 | - (NSString *)rawClassName; 39 | 40 | @end 41 | 42 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 43 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinObject.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinObject.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/4/20. 8 | // https://lookin.work 9 | // 10 | 11 | #import "LookinObject.h" 12 | #import "LookinIvarTrace.h" 13 | #import "NSArray+Lookin.h" 14 | #import "NSString+Lookin.h" 15 | 16 | #if TARGET_OS_IPHONE 17 | #import "NSObject+LookinServer.h" 18 | #endif 19 | 20 | @implementation LookinObject 21 | 22 | #if TARGET_OS_IPHONE 23 | + (instancetype)instanceWithObject:(NSObject *)object { 24 | LookinObject *lookinObj = [LookinObject new]; 25 | lookinObj.oid = [object lks_registerOid]; 26 | 27 | lookinObj.memoryAddress = [NSString stringWithFormat:@"%p", object]; 28 | lookinObj.classChainList = [object lks_classChainList]; 29 | 30 | lookinObj.specialTrace = object.lks_specialTrace; 31 | lookinObj.ivarTraces = object.lks_ivarTraces; 32 | 33 | return lookinObj; 34 | } 35 | #endif 36 | 37 | #pragma mark - 38 | 39 | - (id)copyWithZone:(NSZone *)zone { 40 | LookinObject *newObject = [[LookinObject allocWithZone:zone] init]; 41 | newObject.oid = self.oid; 42 | newObject.memoryAddress = self.memoryAddress; 43 | newObject.classChainList = self.classChainList; 44 | newObject.specialTrace = self.specialTrace; 45 | newObject.ivarTraces = [self.ivarTraces lookin_map:^id(NSUInteger idx, LookinIvarTrace *value) { 46 | return value.copy; 47 | }]; 48 | return newObject; 49 | } 50 | 51 | #pragma mark - 52 | 53 | - (void)encodeWithCoder:(NSCoder *)aCoder { 54 | [aCoder encodeObject:@(self.oid) forKey:@"oid"]; 55 | [aCoder encodeObject:self.memoryAddress forKey:@"memoryAddress"]; 56 | [aCoder encodeObject:self.classChainList forKey:@"classChainList"]; 57 | [aCoder encodeObject:self.specialTrace forKey:@"specialTrace"]; 58 | [aCoder encodeObject:self.ivarTraces forKey:@"ivarTraces"]; 59 | } 60 | 61 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 62 | if (self = [super init]) { 63 | self.oid = [(NSNumber *)[aDecoder decodeObjectForKey:@"oid"] unsignedLongValue]; 64 | self.memoryAddress = [aDecoder decodeObjectForKey:@"memoryAddress"]; 65 | self.classChainList = [aDecoder decodeObjectForKey:@"classChainList"]; 66 | self.specialTrace = [aDecoder decodeObjectForKey:@"specialTrace"]; 67 | self.ivarTraces = [aDecoder decodeObjectForKey:@"ivarTraces"]; 68 | } 69 | return self; 70 | } 71 | 72 | + (BOOL)supportsSecureCoding { 73 | return YES; 74 | } 75 | 76 | - (NSString *)rawClassName { 77 | return self.classChainList.firstObject; 78 | } 79 | 80 | @end 81 | 82 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 83 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinStaticAsyncUpdateTask.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinStaticAsyncUpdateTask.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/6/21. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinDefines.h" 14 | 15 | typedef NS_ENUM(NSInteger, LookinStaticAsyncUpdateTaskType) { 16 | LookinStaticAsyncUpdateTaskTypeNoScreenshot, 17 | LookinStaticAsyncUpdateTaskTypeSoloScreenshot, 18 | LookinStaticAsyncUpdateTaskTypeGroupScreenshot 19 | }; 20 | 21 | typedef NS_ENUM(NSInteger, LookinDetailUpdateTaskAttrRequest) { 22 | /// 由 Server 端自己决定:同一批 task 里,server 端会保证同一个 layer 只会构造一次 attr 23 | /// 在 Lookin turbo 模式下,由于同一个 layer 的 task 可能位于不同批的 task 里,因此这会导致冗余的 attr 构造行为、浪费一定时间 24 | LookinDetailUpdateTaskAttrRequest_Automatic, 25 | /// 需要返回 attr 26 | LookinDetailUpdateTaskAttrRequest_Need, 27 | /// 不需要返回 attr 28 | LookinDetailUpdateTaskAttrRequest_NotNeed 29 | }; 30 | 31 | /// 业务重写了 isEqual 32 | @interface LookinStaticAsyncUpdateTask : NSObject 33 | 34 | @property(nonatomic, assign) unsigned long oid; 35 | 36 | @property(nonatomic, assign) LookinStaticAsyncUpdateTaskType taskType; 37 | 38 | /// 是否需要返回 attr 数据,默认为 Automatic 39 | /// Client 1.0.7 & Server 1.2.7 开始支持这个参数 40 | @property(nonatomic, assign) LookinDetailUpdateTaskAttrRequest attrRequest; 41 | 42 | /// 如果置为 YES,则 server 侧会返回这些基础信息:frameValue, boundsValue, hiddenValue, alphaValue 43 | /// 默认为 NO 44 | /// Client 1.0.7 & Server 1.2.7 开始支持这个参数 45 | @property(nonatomic, assign) BOOL needBasisVisualInfo; 46 | 47 | /// 如果置为 YES,则 server 侧会返回 subitems 48 | /// 默认为 NO 49 | /// Client 1.0.7 & Server 1.2.7 开始支持这个参数 50 | @property(nonatomic, assign) BOOL needSubitems; 51 | 52 | /// Client 1.0.4 开始加入这个参数 53 | @property(nonatomic, copy) NSString *clientReadableVersion; 54 | 55 | #pragma mark - Non Coding 56 | 57 | @property(nonatomic, assign) CGSize frameSize; 58 | 59 | @end 60 | 61 | @interface LookinStaticAsyncUpdateTasksPackage : NSObject 62 | 63 | @property(nonatomic, copy) NSArray *tasks; 64 | 65 | @end 66 | 67 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 68 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinTuple.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinTuples.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/14. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @interface LookinTwoTuple : NSObject 16 | 17 | @property(nonatomic, strong) NSObject *first; 18 | @property(nonatomic, strong) NSObject *second; 19 | 20 | @end 21 | 22 | @interface LookinStringTwoTuple : NSObject 23 | 24 | + (instancetype)tupleWithFirst:(NSString *)firstString second:(NSString *)secondString; 25 | 26 | @property(nonatomic, copy) NSString *first; 27 | @property(nonatomic, copy) NSString *second; 28 | 29 | @end 30 | 31 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 32 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinTuple.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinTuples.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/14. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinTuple.h" 14 | 15 | @implementation LookinTwoTuple 16 | 17 | - (void)encodeWithCoder:(NSCoder *)aCoder { 18 | [aCoder encodeObject:self.first forKey:@"first"]; 19 | [aCoder encodeObject:self.second forKey:@"second"]; 20 | } 21 | 22 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 23 | if (self = [super init]) { 24 | self.first = [aDecoder decodeObjectForKey:@"first"]; 25 | self.second = [aDecoder decodeObjectForKey:@"second"]; 26 | } 27 | return self; 28 | } 29 | 30 | + (BOOL)supportsSecureCoding { 31 | return YES; 32 | } 33 | 34 | - (NSUInteger)hash { 35 | return self.first.hash ^ self.second.hash; 36 | } 37 | 38 | - (BOOL)isEqual:(id)object { 39 | if (self == object) { 40 | return YES; 41 | } 42 | if (![object isKindOfClass:[LookinTwoTuple class]]) { 43 | return NO; 44 | } 45 | LookinTwoTuple *comparedObj = object; 46 | if ([self.first isEqual:comparedObj.first] && [self.second isEqual:comparedObj.second]) { 47 | return YES; 48 | } 49 | return NO; 50 | } 51 | 52 | @end 53 | 54 | @implementation LookinStringTwoTuple 55 | 56 | + (instancetype)tupleWithFirst:(NSString *)firstString second:(NSString *)secondString { 57 | LookinStringTwoTuple *tuple = [LookinStringTwoTuple new]; 58 | tuple.first = firstString; 59 | tuple.second = secondString; 60 | return tuple; 61 | } 62 | 63 | #pragma mark - 64 | 65 | - (id)copyWithZone:(NSZone *)zone { 66 | LookinStringTwoTuple *newTuple = [[LookinStringTwoTuple allocWithZone:zone] init]; 67 | newTuple.first = self.first; 68 | newTuple.second = self.second; 69 | return newTuple; 70 | } 71 | 72 | #pragma mark - 73 | 74 | - (void)encodeWithCoder:(NSCoder *)aCoder { 75 | [aCoder encodeObject:self.first forKey:@"first"]; 76 | [aCoder encodeObject:self.second forKey:@"second"]; 77 | } 78 | 79 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 80 | if (self = [super init]) { 81 | self.first = [aDecoder decodeObjectForKey:@"first"]; 82 | self.second = [aDecoder decodeObjectForKey:@"second"]; 83 | } 84 | return self; 85 | } 86 | 87 | + (BOOL)supportsSecureCoding { 88 | return YES; 89 | } 90 | 91 | @end 92 | 93 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 94 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinWeakContainer.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinWeakContainer.h 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/14. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | @interface LookinWeakContainer : NSObject 16 | 17 | + (instancetype)containerWithObject:(id)object; 18 | 19 | @property (nonatomic, weak) id object; 20 | 21 | @end 22 | 23 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 24 | -------------------------------------------------------------------------------- /Src/Main/Shared/LookinWeakContainer.m: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // LookinWeakContainer.m 5 | // Lookin 6 | // 7 | // Created by Li Kai on 2019/8/14. 8 | // https://lookin.work 9 | // 10 | 11 | 12 | 13 | #import "LookinWeakContainer.h" 14 | 15 | @implementation LookinWeakContainer 16 | 17 | + (instancetype)containerWithObject:(id)object { 18 | LookinWeakContainer *container = [LookinWeakContainer new]; 19 | container.object = object; 20 | return container; 21 | } 22 | 23 | - (NSUInteger)hash { 24 | return [self.object hash]; 25 | } 26 | 27 | - (BOOL)isEqual:(id)object { 28 | if (self == object) { 29 | return YES; 30 | } 31 | if (![object isKindOfClass:[LookinWeakContainer class]]) { 32 | return NO; 33 | } 34 | LookinWeakContainer *comparedObj = object; 35 | if ([self.object isEqual:comparedObj.object]) { 36 | return YES; 37 | } 38 | return NO; 39 | } 40 | 41 | @end 42 | 43 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 44 | -------------------------------------------------------------------------------- /Src/Main/Shared/Peertalk/Lookin_PTPrivate.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | 4 | 5 | #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (!defined(__IPHONE_6_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0)) || \ 6 | (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (!defined(__MAC_10_8) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8)) 7 | #define PT_DISPATCH_RETAIN_RELEASE 1 8 | #else 9 | #define PT_DISPATCH_RETAIN_RELEASE 0 10 | #endif 11 | 12 | #if PT_DISPATCH_RETAIN_RELEASE 13 | #define PT_PRECISE_LIFETIME 14 | #define PT_PRECISE_LIFETIME_UNUSED 15 | #else 16 | #define PT_PRECISE_LIFETIME __attribute__((objc_precise_lifetime)) 17 | #define PT_PRECISE_LIFETIME_UNUSED __attribute__((objc_precise_lifetime, unused)) 18 | #endif 19 | 20 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 21 | -------------------------------------------------------------------------------- /Src/Main/Shared/Peertalk/Lookin_PTUSBHub.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | 4 | 5 | #include 6 | #import 7 | 8 | // Lookin_PTUSBDeviceDidAttachNotification 9 | // Posted when a device has been attached. Also posted for each device that is 10 | // already attached when the Lookin_PTUSBHub starts listening. 11 | // 12 | // .userInfo = { 13 | // DeviceID = 3; 14 | // MessageType = Attached; 15 | // Properties = { 16 | // ConnectionSpeed = 480000000; 17 | // ConnectionType = USB; 18 | // DeviceID = 3; 19 | // LocationID = 1234567890; 20 | // ProductID = 1234; 21 | // SerialNumber = 0123456789abcdef0123456789abcdef01234567; 22 | // }; 23 | // } 24 | // 25 | FOUNDATION_EXPORT NSString * const Lookin_PTUSBDeviceDidAttachNotification; 26 | 27 | // Lookin_PTUSBDeviceDidDetachNotification 28 | // Posted when a device has been detached. 29 | // 30 | // .userInfo = { 31 | // DeviceID = 3; 32 | // MessageType = Detached; 33 | // } 34 | // 35 | FOUNDATION_EXPORT NSString * const Lookin_PTUSBDeviceDidDetachNotification; 36 | 37 | // NSError domain 38 | FOUNDATION_EXPORT NSString * const Lookin_PTUSBHubErrorDomain; 39 | 40 | // Error codes returned with NSError.code for NSError domain Lookin_PTUSBHubErrorDomain 41 | typedef enum { 42 | PTUSBHubErrorBadDevice = 2, 43 | PTUSBHubErrorConnectionRefused = 3, 44 | } PTUSBHubError; 45 | 46 | @interface Lookin_PTUSBHub : NSObject 47 | 48 | // Shared, implicitly opened hub. 49 | + (Lookin_PTUSBHub*)sharedHub; 50 | 51 | // Connect to a TCP *port* on a device, while the actual transport is over USB. 52 | // Upon success, *error* is nil and *channel* is a duplex I/O channel. 53 | // You can retrieve the underlying file descriptor using 54 | // dispatch_io_get_descriptor(channel). The dispatch_io_t channel behaves just 55 | // like any stream type dispatch_io_t, making it possible to use the same logic 56 | // for both USB bridged connections and e.g. ethernet-based connections. 57 | // 58 | // *onStart* is called either when a connection failed, in which case the error 59 | // argument is non-nil, or when the connection was successfully established (the 60 | // error argument is nil). Must not be NULL. 61 | // 62 | // *onEnd* is called when a connection was open and just did close. If the error 63 | // argument is non-nil, the channel closed because of an error. Pass NULL for no 64 | // callback. 65 | // 66 | - (void)connectToDevice:(NSNumber*)deviceID 67 | port:(int)port 68 | onStart:(void(^)(NSError *error, dispatch_io_t channel))onStart 69 | onEnd:(void(^)(NSError *error))onEnd; 70 | 71 | // Start listening for devices. You only need to invoke this method on custom 72 | // instances to start receiving notifications. The shared instance returned from 73 | // +sharedHub is always in listening mode. 74 | // 75 | // *onStart* is called either when the system failed to start listening, in 76 | // which case the error argument is non-nil, or when the receiver is listening. 77 | // Pass NULL for no callback. 78 | // 79 | // *onEnd* is called when listening stopped. If the error argument is non-nil, 80 | // listening stopped because of an error. Pass NULL for no callback. 81 | // 82 | - (void)listenOnQueue:(dispatch_queue_t)queue 83 | onStart:(void(^)(NSError*))onStart 84 | onEnd:(void(^)(NSError*))onEnd; 85 | 86 | @end 87 | 88 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 89 | -------------------------------------------------------------------------------- /Src/Main/Shared/Peertalk/Peertalk.h: -------------------------------------------------------------------------------- 1 | #ifdef SHOULD_COMPILE_LOOKIN_SERVER 2 | 3 | // 4 | // Peertalk.h 5 | // Peertalk 6 | // 7 | // Created by Marek Cirkos on 12/04/2016. 8 | // 9 | // 10 | 11 | 12 | 13 | #import 14 | 15 | //! Project version number for Peertalk. 16 | FOUNDATION_EXPORT double PeertalkVersionNumber; 17 | 18 | //! Project version string for Peertalk. 19 | FOUNDATION_EXPORT const unsigned char PeertalkVersionString[]; 20 | 21 | // In this header, you should import all the public headers of your framework using statements like #import 22 | 23 | 24 | #import "Lookin_PTChannel.h" 25 | #import "Lookin_PTProtocol.h" 26 | #import "Lookin_PTUSBHub.h" 27 | 28 | #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ 29 | --------------------------------------------------------------------------------