1
This commit is contained in:
23
Pods/LookinServer/Src/Main/Shared/Category/CALayer+Lookin.h
generated
Normal file
23
Pods/LookinServer/Src/Main/Shared/Category/CALayer+Lookin.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// CALayer+Lookin.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/8/4.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface CALayer (Lookin)
|
||||
|
||||
- (void)lookin_removeImplicitAnimations;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
70
Pods/LookinServer/Src/Main/Shared/Category/CALayer+Lookin.m
generated
Normal file
70
Pods/LookinServer/Src/Main/Shared/Category/CALayer+Lookin.m
generated
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// CALayer+Lookin.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/8/4.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "CALayer+Lookin.h"
|
||||
|
||||
@implementation CALayer (Lookin)
|
||||
|
||||
- (void)lookin_removeImplicitAnimations {
|
||||
NSMutableDictionary<NSString *, id<CAAction>> *actions = @{NSStringFromSelector(@selector(bounds)): [NSNull null],
|
||||
NSStringFromSelector(@selector(position)): [NSNull null],
|
||||
NSStringFromSelector(@selector(zPosition)): [NSNull null],
|
||||
NSStringFromSelector(@selector(anchorPoint)): [NSNull null],
|
||||
NSStringFromSelector(@selector(anchorPointZ)): [NSNull null],
|
||||
NSStringFromSelector(@selector(transform)): [NSNull null],
|
||||
NSStringFromSelector(@selector(sublayerTransform)): [NSNull null],
|
||||
NSStringFromSelector(@selector(masksToBounds)): [NSNull null],
|
||||
NSStringFromSelector(@selector(contents)): [NSNull null],
|
||||
NSStringFromSelector(@selector(contentsRect)): [NSNull null],
|
||||
NSStringFromSelector(@selector(contentsScale)): [NSNull null],
|
||||
NSStringFromSelector(@selector(contentsCenter)): [NSNull null],
|
||||
NSStringFromSelector(@selector(minificationFilterBias)): [NSNull null],
|
||||
NSStringFromSelector(@selector(backgroundColor)): [NSNull null],
|
||||
NSStringFromSelector(@selector(cornerRadius)): [NSNull null],
|
||||
NSStringFromSelector(@selector(borderWidth)): [NSNull null],
|
||||
NSStringFromSelector(@selector(borderColor)): [NSNull null],
|
||||
NSStringFromSelector(@selector(opacity)): [NSNull null],
|
||||
NSStringFromSelector(@selector(compositingFilter)): [NSNull null],
|
||||
NSStringFromSelector(@selector(filters)): [NSNull null],
|
||||
NSStringFromSelector(@selector(backgroundFilters)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shouldRasterize)): [NSNull null],
|
||||
NSStringFromSelector(@selector(rasterizationScale)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shadowColor)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shadowOpacity)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shadowOffset)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shadowRadius)): [NSNull null],
|
||||
NSStringFromSelector(@selector(shadowPath)): [NSNull null]}.mutableCopy;
|
||||
|
||||
if ([self isKindOfClass:[CAShapeLayer class]]) {
|
||||
[actions addEntriesFromDictionary:@{NSStringFromSelector(@selector(path)): [NSNull null],
|
||||
NSStringFromSelector(@selector(fillColor)): [NSNull null],
|
||||
NSStringFromSelector(@selector(strokeColor)): [NSNull null],
|
||||
NSStringFromSelector(@selector(strokeStart)): [NSNull null],
|
||||
NSStringFromSelector(@selector(strokeEnd)): [NSNull null],
|
||||
NSStringFromSelector(@selector(lineWidth)): [NSNull null],
|
||||
NSStringFromSelector(@selector(miterLimit)): [NSNull null],
|
||||
NSStringFromSelector(@selector(lineDashPhase)): [NSNull null]}];
|
||||
}
|
||||
|
||||
if ([self isKindOfClass:[CAGradientLayer class]]) {
|
||||
[actions addEntriesFromDictionary:@{NSStringFromSelector(@selector(colors)): [NSNull null],
|
||||
NSStringFromSelector(@selector(locations)): [NSNull null],
|
||||
NSStringFromSelector(@selector(startPoint)): [NSNull null],
|
||||
NSStringFromSelector(@selector(endPoint)): [NSNull null]}];
|
||||
}
|
||||
|
||||
self.actions = actions;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
27
Pods/LookinServer/Src/Main/Shared/Category/Color+Lookin.h
generated
Normal file
27
Pods/LookinServer/Src/Main/Shared/Category/Color+Lookin.h
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// Color+Lookin.h
|
||||
// LookinShared
|
||||
//
|
||||
// Created by 李凯 on 2022/4/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
@interface NSColor (Lookin)
|
||||
|
||||
+ (instancetype)lookin_colorFromRGBAComponents:(NSArray<NSNumber *> *)components;
|
||||
|
||||
- (NSArray<NSNumber *> *)lookin_rgbaComponents;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
42
Pods/LookinServer/Src/Main/Shared/Category/Color+Lookin.m
generated
Normal file
42
Pods/LookinServer/Src/Main/Shared/Category/Color+Lookin.m
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// Color+Lookin.m
|
||||
// LookinShared
|
||||
//
|
||||
// Created by 李凯 on 2022/4/2.
|
||||
//
|
||||
|
||||
#import "Image+Lookin.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
@implementation NSColor (Lookin)
|
||||
|
||||
+ (instancetype)lookin_colorFromRGBAComponents:(NSArray<NSNumber *> *)components {
|
||||
if (!components) {
|
||||
return nil;
|
||||
}
|
||||
if (components.count != 4) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
NSColor *color = [NSColor colorWithRed:components[0].doubleValue green:components[1].doubleValue blue:components[2].doubleValue alpha:components[3].doubleValue];
|
||||
return color;
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)lookin_rgbaComponents {
|
||||
NSColor *rgbColor = [self colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
||||
CGFloat r, g, b, a;
|
||||
[rgbColor getRed:&r green:&g blue:&b alpha:&a];
|
||||
NSArray<NSNumber *> *rgba = @[@(r), @(g), @(b), @(a)];
|
||||
return rgba;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
25
Pods/LookinServer/Src/Main/Shared/Category/Image+Lookin.h
generated
Normal file
25
Pods/LookinServer/Src/Main/Shared/Category/Image+Lookin.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// Image+Lookin.h
|
||||
// LookinShared
|
||||
//
|
||||
// Created by 李凯 on 2022/4/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
@interface NSImage (LookinClient)
|
||||
|
||||
- (NSData *)lookin_data;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
26
Pods/LookinServer/Src/Main/Shared/Category/Image+Lookin.m
generated
Normal file
26
Pods/LookinServer/Src/Main/Shared/Category/Image+Lookin.m
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// Image+Lookin.m
|
||||
// LookinShared
|
||||
//
|
||||
// Created by 李凯 on 2022/4/2.
|
||||
//
|
||||
|
||||
#import "Image+Lookin.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
@implementation NSImage (LookinClient)
|
||||
|
||||
- (NSData *)lookin_data {
|
||||
return [self TIFFRepresentation];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
72
Pods/LookinServer/Src/Main/Shared/Category/NSArray+Lookin.h
generated
Normal file
72
Pods/LookinServer/Src/Main/Shared/Category/NSArray+Lookin.h
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSArray+Lookin.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/9/3.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
@interface NSArray<__covariant ValueType> (Lookin)
|
||||
|
||||
/**
|
||||
初始化一个新的 NSArray 并返回,新数组的长度为 count,如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则会舍弃多余的元素,被舍弃的元素会作为参数传入 removeBlock。最终,新数组的所有元素均会作为参数被传入 doBlock。
|
||||
*/
|
||||
- (NSArray<ValueType> *)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));
|
||||
|
||||
+ (NSArray *)lookin_arrayWithCount:(NSUInteger)count block:(id (^)(NSUInteger idx))block;
|
||||
|
||||
/**
|
||||
检查 index 位置是否有元素存在
|
||||
*/
|
||||
- (BOOL)lookin_hasIndex:(NSInteger)index;
|
||||
|
||||
- (NSArray *)lookin_map:(id (^)(NSUInteger idx, ValueType value))block;
|
||||
|
||||
- (NSArray<ValueType> *)lookin_filter:(BOOL (^)( ValueType obj))block;
|
||||
|
||||
- (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
/// 返回最后一个 block 返回 YES 的元素
|
||||
- (ValueType)lookin_lastFiltered:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
- (id)lookin_reduce:(id (^)(id accumulator, NSUInteger idx, ValueType obj))block;
|
||||
|
||||
- (CGFloat)lookin_reduceCGFloat:(CGFloat (^)(CGFloat accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(CGFloat)initialAccumlator;
|
||||
- (NSInteger)lookin_reduceInteger:(NSInteger (^)(NSInteger accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(NSInteger)initialAccumlator;
|
||||
|
||||
- (BOOL)lookin_all:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
- (BOOL)lookin_any:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
- (NSArray<ValueType> *)lookin_arrayByRemovingObject:(ValueType)obj;
|
||||
|
||||
- (NSArray<ValueType> *)lookin_nonredundantArray;
|
||||
|
||||
- (ValueType)lookin_safeObjectAtIndex:(NSInteger)idx;
|
||||
|
||||
/// 字符串长度从短到长,即 length 小的字符串的 idx 更小
|
||||
- (NSArray<ValueType> *)lookin_sortedArrayByStringLength;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSMutableArray<ValueType> (Lookin)
|
||||
|
||||
/**
|
||||
如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则多余的元素会被作为参数传入 notDequeued。然后从 idx 为 0 算起,前 count 个元素会被作为参数传入 doBlock
|
||||
*/
|
||||
- (void)lookin_dequeueWithCount:(NSUInteger)count add:(ValueType (^)(NSUInteger idx))addBlock notDequeued:(void (^)(NSUInteger idx, ValueType obj))notDequeuedBlock doNext:(void (^)(NSUInteger idx, ValueType obj))doBlock;
|
||||
|
||||
- (void)lookin_removeObjectsPassingTest:(BOOL (^)(NSUInteger idx, ValueType obj))block;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
300
Pods/LookinServer/Src/Main/Shared/Category/NSArray+Lookin.m
generated
Normal file
300
Pods/LookinServer/Src/Main/Shared/Category/NSArray+Lookin.m
generated
Normal file
@@ -0,0 +1,300 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSArray+Lookin.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/9/3.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "NSArray+Lookin.h"
|
||||
|
||||
@implementation NSArray (Lookin)
|
||||
|
||||
- (NSArray *)lookin_resizeWithCount:(NSUInteger)count add:(id (^)(NSUInteger idx))addBlock remove:(void (^)(NSUInteger idx, id obj))removeBlock doNext:(void (^)(NSUInteger idx, id obj))doBlock {
|
||||
NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:count];
|
||||
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
if (self.count > i) {
|
||||
id obj = [self objectAtIndex:i];
|
||||
[resultArray addObject:obj];
|
||||
if (doBlock) {
|
||||
doBlock(i, obj);
|
||||
}
|
||||
} else {
|
||||
if (addBlock) {
|
||||
id newObj = addBlock(i);
|
||||
if (newObj) {
|
||||
[resultArray addObject:newObj];
|
||||
if (doBlock) {
|
||||
doBlock(i, newObj);
|
||||
}
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removeBlock) {
|
||||
if (self.count > count) {
|
||||
for (NSUInteger i = count; i < self.count; i++) {
|
||||
id obj = [self objectAtIndex:i];
|
||||
removeBlock(i, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [resultArray copy];
|
||||
}
|
||||
|
||||
+ (NSArray *)lookin_arrayWithCount:(NSUInteger)count block:(id (^)(NSUInteger idx))block {
|
||||
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
id obj = block(i);
|
||||
if (obj) {
|
||||
[array addObject:obj];
|
||||
}
|
||||
}
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
- (BOOL)lookin_hasIndex:(NSInteger)index {
|
||||
if (index == NSNotFound || index < 0) {
|
||||
return NO;
|
||||
}
|
||||
return self.count > index;
|
||||
}
|
||||
|
||||
- (NSArray *)lookin_map:(id (^)(NSUInteger , id))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:self.count];
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
id newObj = block(idx, obj);
|
||||
if (newObj) {
|
||||
[array addObject:newObj];
|
||||
}
|
||||
}];
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
- (NSArray *)lookin_filter:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *mArray = [NSMutableArray array];
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
[mArray addObject:obj];
|
||||
}
|
||||
}];
|
||||
return [mArray copy];
|
||||
}
|
||||
|
||||
- (id)lookin_firstFiltered:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block id targetObj = nil;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
targetObj = obj;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return targetObj;
|
||||
}
|
||||
|
||||
- (id)lookin_lastFiltered:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block id targetObj = nil;
|
||||
[self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
targetObj = obj;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return targetObj;
|
||||
}
|
||||
|
||||
- (id)lookin_reduce:(id (^)(id accumulator, NSUInteger idx, id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block id accumulator = nil;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
accumulator = block(accumulator, idx, obj);
|
||||
}];
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
- (CGFloat)lookin_reduceCGFloat:(CGFloat (^)(CGFloat accumulator, NSUInteger idx, id obj))block initialAccumlator:(CGFloat)initialAccumlator {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return initialAccumlator;
|
||||
}
|
||||
|
||||
__block CGFloat accumulator = initialAccumlator;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
accumulator = block(accumulator, idx, obj);
|
||||
}];
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
- (NSInteger)lookin_reduceInteger:(NSInteger (^)(NSInteger, NSUInteger, id))block initialAccumlator:(NSInteger)initialAccumlator {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return initialAccumlator;
|
||||
}
|
||||
|
||||
__block NSInteger accumulator = initialAccumlator;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
accumulator = block(accumulator, idx, obj);
|
||||
}];
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
- (BOOL)lookin_all:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return NO;
|
||||
}
|
||||
__block BOOL allPass = YES;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
BOOL boolValue = block(obj);
|
||||
if (!boolValue) {
|
||||
allPass = NO;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return allPass;
|
||||
}
|
||||
|
||||
- (BOOL)lookin_any:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return NO;
|
||||
}
|
||||
__block BOOL anyPass = NO;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
BOOL boolValue = block(obj);
|
||||
if (boolValue) {
|
||||
anyPass = YES;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return anyPass;
|
||||
}
|
||||
|
||||
- (NSArray *)lookin_arrayByRemovingObject:(id)obj {
|
||||
if (!obj || ![self containsObject:obj]) {
|
||||
return self;
|
||||
}
|
||||
NSMutableArray *mutableArray = self.mutableCopy;
|
||||
[mutableArray removeObject:obj];
|
||||
return mutableArray.copy;
|
||||
}
|
||||
|
||||
- (NSArray *)lookin_nonredundantArray {
|
||||
NSSet *set = [NSSet setWithArray:self];
|
||||
NSArray *newArray = [set allObjects];
|
||||
return newArray;
|
||||
}
|
||||
|
||||
- (id)lookin_safeObjectAtIndex:(NSInteger)idx {
|
||||
if (idx == NSNotFound || idx < 0) {
|
||||
return nil;
|
||||
}
|
||||
if (self.count <= idx) {
|
||||
return nil;
|
||||
}
|
||||
return [self objectAtIndex:idx];
|
||||
}
|
||||
|
||||
- (NSArray *)lookin_sortedArrayByStringLength {
|
||||
NSArray<NSString *> *sortedArray = [self sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
|
||||
if (obj1.length > obj2.length) {
|
||||
return NSOrderedDescending;
|
||||
} else if (obj1.length == obj2.length) {
|
||||
return NSOrderedSame;
|
||||
} else {
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
}];
|
||||
return sortedArray;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSMutableArray (Lookin)
|
||||
|
||||
- (void)lookin_dequeueWithCount:(NSUInteger)count add:(id (^)(NSUInteger idx))addBlock notDequeued:(void (^)(NSUInteger idx, id obj))notDequeuedBlock doNext:(void (^)(NSUInteger idx, id obj))doBlock {
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
if ([self lookin_hasIndex:i]) {
|
||||
id obj = [self objectAtIndex:i];
|
||||
if (doBlock) {
|
||||
doBlock(i, obj);
|
||||
}
|
||||
} else {
|
||||
if (addBlock) {
|
||||
id newObj = addBlock(i);
|
||||
if (newObj) {
|
||||
[self addObject:newObj];
|
||||
if (doBlock) {
|
||||
doBlock(i, newObj);
|
||||
}
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notDequeuedBlock) {
|
||||
if (self.count > count) {
|
||||
for (NSUInteger i = count; i < self.count; i++) {
|
||||
id obj = [self objectAtIndex:i];
|
||||
notDequeuedBlock(i, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_removeObjectsPassingTest:(BOOL (^)(NSUInteger idx, id obj))block {
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull currentObj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
BOOL boolValue = block(idx, currentObj);
|
||||
if (boolValue) {
|
||||
[indexSet addIndex:idx];
|
||||
}
|
||||
}];
|
||||
[self removeObjectsAtIndexes:indexSet];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
108
Pods/LookinServer/Src/Main/Shared/Category/NSObject+Lookin.h
generated
Normal file
108
Pods/LookinServer/Src/Main/Shared/Category/NSObject+Lookin.h
generated
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSObject+Lookin.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/12/22.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinCodingValueType.h"
|
||||
|
||||
@interface NSObject (Lookin)
|
||||
|
||||
#pragma mark - Data Bind
|
||||
|
||||
/**
|
||||
给对象绑定上另一个对象以供后续取出使用,如果 object 传入 nil 则会清除该 key 之前绑定的对象
|
||||
|
||||
@attention 被绑定的对象会被 strong 强引用
|
||||
@note 内部是使用 objc_setAssociatedObject / objc_getAssociatedObject 来实现
|
||||
|
||||
@code
|
||||
- (UITableViewCell *)cellForIndexPath:(NSIndexPath *)indexPath {
|
||||
// 1)在这里给 button 绑定上 indexPath 对象
|
||||
[cell lookin_bindObject:indexPath forKey:@"indexPath"];
|
||||
}
|
||||
|
||||
- (void)didTapButton:(UIButton *)button {
|
||||
// 2)在这里取出被点击的 button 的 indexPath 对象
|
||||
NSIndexPath *indexPathTapped = [button lookin_getBindObjectForKey:@"indexPath"];
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
- (void)lookin_bindObject:(id)object forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
给对象绑定上另一个对象以供后续取出使用,但相比于 lookin_bindObject:forKey:,该方法不会 strong 强引用传入的 object
|
||||
*/
|
||||
- (void)lookin_bindObjectWeakly:(id)object forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
取出之前使用 bind 方法绑定的对象
|
||||
*/
|
||||
- (id)lookin_getBindObjectForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
给对象绑定上一个 double 值以供后续取出使用
|
||||
*/
|
||||
- (void)lookin_bindDouble:(double)doubleValue forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
取出之前用 lookin_bindDouble:forKey: 绑定的值
|
||||
*/
|
||||
- (double)lookin_getBindDoubleForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
给对象绑定上一个 BOOL 值以供后续取出使用
|
||||
*/
|
||||
- (void)lookin_bindBOOL:(BOOL)boolValue forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
取出之前用 lookin_bindBOOL:forKey: 绑定的值
|
||||
*/
|
||||
- (BOOL)lookin_getBindBOOLForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
给对象绑定上一个 long 值以供后续取出使用
|
||||
*/
|
||||
- (void)lookin_bindLong:(long)longValue forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
取出之前用 lookin_bindLong:forKey: 绑定的值
|
||||
*/
|
||||
- (long)lookin_getBindLongForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
给对象绑定上一个 CGPoint 值以供后续取出使用
|
||||
*/
|
||||
- (void)lookin_bindPoint:(CGPoint)pointValue forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
取出之前用 lookin_bindPoint:forKey: 绑定的值
|
||||
*/
|
||||
- (CGPoint)lookin_getBindPointForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
移除之前使用 bind 方法绑定的对象
|
||||
*/
|
||||
- (void)lookin_clearBindForKey:(NSString *)key;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSObject (Lookin_Coding)
|
||||
|
||||
/// 会把 NSImage/UIImage 转换为 NSData,把 NSColor/UIColor 转换回 NSNumber 数组(rgba)
|
||||
- (id)lookin_encodedObjectWithType:(LookinCodingValueType)type;
|
||||
/// 会把 NSData 转换回 NSImage/UIImage,把 NSNumber 数组(rgba) 转换为 NSColor/UIColor
|
||||
- (id)lookin_decodedObjectWithType:(LookinCodingValueType)type;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
238
Pods/LookinServer/Src/Main/Shared/Category/NSObject+Lookin.m
generated
Normal file
238
Pods/LookinServer/Src/Main/Shared/Category/NSObject+Lookin.m
generated
Normal file
@@ -0,0 +1,238 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSObject+Lookin.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/12/22.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "NSObject+Lookin.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "TargetConditionals.h"
|
||||
#import "LookinWeakContainer.h"
|
||||
|
||||
@implementation NSObject (Lookin)
|
||||
|
||||
#pragma mark - Data Bind
|
||||
|
||||
static char kAssociatedObjectKey_LookinAllBindObjects;
|
||||
- (NSMutableDictionary<id, id> *)lookin_allBindObjects {
|
||||
NSMutableDictionary<id, id> *dict = objc_getAssociatedObject(self, &kAssociatedObjectKey_LookinAllBindObjects);
|
||||
if (!dict) {
|
||||
dict = [NSMutableDictionary dictionary];
|
||||
objc_setAssociatedObject(self, &kAssociatedObjectKey_LookinAllBindObjects, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
- (void)lookin_bindObject:(id)object forKey:(NSString *)key {
|
||||
if (!key.length) {
|
||||
NSAssert(NO, @"");
|
||||
return;
|
||||
}
|
||||
@synchronized (self) {
|
||||
if (object) {
|
||||
[[self lookin_allBindObjects] setObject:object forKey:key];
|
||||
} else {
|
||||
[[self lookin_allBindObjects] removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)lookin_getBindObjectForKey:(NSString *)key {
|
||||
if (!key.length) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
@synchronized (self) {
|
||||
id storedObj = [[self lookin_allBindObjects] objectForKey:key];
|
||||
if ([storedObj isKindOfClass:[LookinWeakContainer class]]) {
|
||||
storedObj = [(LookinWeakContainer *)storedObj object];
|
||||
}
|
||||
return storedObj;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_bindObjectWeakly:(id)object forKey:(NSString *)key {
|
||||
if (!key.length) {
|
||||
NSAssert(NO, @"");
|
||||
return;
|
||||
}
|
||||
if (object) {
|
||||
LookinWeakContainer *container = [[LookinWeakContainer alloc] init];
|
||||
container.object = object;
|
||||
[self lookin_bindObject:container forKey:key];
|
||||
} else {
|
||||
[self lookin_bindObject:nil forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_bindDouble:(double)doubleValue forKey:(NSString *)key {
|
||||
[self lookin_bindObject:@(doubleValue) forKey:key];
|
||||
}
|
||||
|
||||
- (double)lookin_getBindDoubleForKey:(NSString *)key {
|
||||
id object = [self lookin_getBindObjectForKey:key];
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
double doubleValue = [(NSNumber *)object doubleValue];
|
||||
return doubleValue;
|
||||
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_bindBOOL:(BOOL)boolValue forKey:(NSString *)key {
|
||||
[self lookin_bindObject:@(boolValue) forKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)lookin_getBindBOOLForKey:(NSString *)key {
|
||||
id object = [self lookin_getBindObjectForKey:key];
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
BOOL boolValue = [(NSNumber *)object boolValue];
|
||||
return boolValue;
|
||||
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_bindLong:(long)longValue forKey:(NSString *)key {
|
||||
[self lookin_bindObject:@(longValue) forKey:key];
|
||||
}
|
||||
|
||||
- (long)lookin_getBindLongForKey:(NSString *)key {
|
||||
id object = [self lookin_getBindObjectForKey:key];
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
long longValue = [(NSNumber *)object longValue];
|
||||
return longValue;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_bindPoint:(CGPoint)pointValue forKey:(NSString *)key {
|
||||
#if TARGET_OS_IPHONE
|
||||
[self lookin_bindObject:[NSValue valueWithCGPoint:pointValue] forKey:key];
|
||||
#elif TARGET_OS_MAC
|
||||
NSPoint nsPoint = NSMakePoint(pointValue.x, pointValue.y);
|
||||
[self lookin_bindObject:[NSValue valueWithPoint:nsPoint] forKey:key];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CGPoint)lookin_getBindPointForKey:(NSString *)key {
|
||||
id object = [self lookin_getBindObjectForKey:key];
|
||||
if ([object isKindOfClass:[NSValue class]]) {
|
||||
#if TARGET_OS_IPHONE
|
||||
CGPoint pointValue = [(NSValue *)object CGPointValue];
|
||||
#elif TARGET_OS_MAC
|
||||
NSPoint nsPointValue = [(NSValue *)object pointValue];
|
||||
CGPoint pointValue = CGPointMake(nsPointValue.x, nsPointValue.y);
|
||||
#endif
|
||||
return pointValue;
|
||||
} else {
|
||||
return CGPointZero;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lookin_clearBindForKey:(NSString *)key {
|
||||
[self lookin_bindObject:nil forKey:key];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObject (Lookin_Coding)
|
||||
|
||||
- (id)lookin_encodedObjectWithType:(LookinCodingValueType)type {
|
||||
if (type == LookinCodingValueTypeColor) {
|
||||
if ([self isKindOfClass:[LookinColor class]]) {
|
||||
CGFloat r, g, b, a;
|
||||
#if TARGET_OS_IPHONE
|
||||
CGFloat white;
|
||||
if ([(UIColor *)self getRed:&r green:&g blue:&b alpha:&a]) {
|
||||
// valid
|
||||
} else if ([(UIColor *)self getWhite:&white alpha:&a]) {
|
||||
r = white;
|
||||
g = white;
|
||||
b = white;
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
a = 0;
|
||||
}
|
||||
#elif TARGET_OS_MAC
|
||||
NSColor *color = [((NSColor *)self) colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
||||
[color getRed:&r green:&g blue:&b alpha:&a];
|
||||
#endif
|
||||
NSArray<NSNumber *> *rgba = @[@(r), @(g), @(b), @(a)];
|
||||
return rgba;
|
||||
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
} else if (type == LookinCodingValueTypeImage) {
|
||||
#if TARGET_OS_IPHONE
|
||||
if ([self isKindOfClass:[UIImage class]]) {
|
||||
UIImage *image = (UIImage *)self;
|
||||
return UIImagePNGRepresentation(image);
|
||||
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
#elif TARGET_OS_MAC
|
||||
if ([self isKindOfClass:[NSImage class]]) {
|
||||
NSImage *image = (NSImage *)self;
|
||||
return [image TIFFRepresentation];
|
||||
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)lookin_decodedObjectWithType:(LookinCodingValueType)type {
|
||||
if (type == LookinCodingValueTypeColor) {
|
||||
if ([self isKindOfClass:[NSArray class]]) {
|
||||
NSArray<NSNumber *> *rgba = (NSArray *)self;
|
||||
CGFloat r = [rgba[0] doubleValue];
|
||||
CGFloat g = [rgba[1] doubleValue];
|
||||
CGFloat b = [rgba[2] doubleValue];
|
||||
CGFloat a = [rgba[3] doubleValue];
|
||||
LookinColor *color = [LookinColor colorWithRed:r green:g blue:b alpha:a];
|
||||
return color;
|
||||
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
} else if (type == LookinCodingValueTypeImage) {
|
||||
if ([self isKindOfClass:[NSData class]]) {
|
||||
LookinImage *image = [[LookinImage alloc] initWithData:(NSData *)self];
|
||||
return image;
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
39
Pods/LookinServer/Src/Main/Shared/Category/NSSet+Lookin.h
generated
Normal file
39
Pods/LookinServer/Src/Main/Shared/Category/NSSet+Lookin.h
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSSet+Lookin.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/1/13.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#import <Appkit/Appkit.h>
|
||||
#endif
|
||||
|
||||
@interface NSSet<__covariant ValueType> (Lookin)
|
||||
|
||||
- (NSSet *)lookin_map:(id (^)(ValueType obj))block;
|
||||
|
||||
- (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
- (NSSet<ValueType> *)lookin_filter:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
|
||||
/**
|
||||
是否有任何一个元素满足某条件
|
||||
@note 元素将被依次传入 block 里,如果任何一个 block 返回 YES,则该方法返回 YES。如果所有 block 均返回 NO,则该方法返回 NO。
|
||||
*/
|
||||
- (BOOL)lookin_any:(BOOL (^)(ValueType obj))block;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
81
Pods/LookinServer/Src/Main/Shared/Category/NSSet+Lookin.m
generated
Normal file
81
Pods/LookinServer/Src/Main/Shared/Category/NSSet+Lookin.m
generated
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSSet+Lookin.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/1/13.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "NSSet+Lookin.h"
|
||||
|
||||
@implementation NSSet (Lookin)
|
||||
|
||||
- (NSSet *)lookin_map:(id (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableSet *newSet = [NSMutableSet setWithCapacity:self.count];
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
id newObj = block(obj);
|
||||
if (newObj) {
|
||||
[newSet addObject:newObj];
|
||||
}
|
||||
}];
|
||||
return [newSet copy];
|
||||
}
|
||||
|
||||
- (id)lookin_firstFiltered:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block id targetObj = nil;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
targetObj = obj;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return targetObj;
|
||||
}
|
||||
|
||||
- (NSSet *)lookin_filter:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableSet *mSet = [NSMutableSet set];
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
[mSet addObject:obj];
|
||||
}
|
||||
}];
|
||||
return [mSet copy];
|
||||
}
|
||||
|
||||
- (BOOL)lookin_any:(BOOL (^)(id obj))block {
|
||||
if (!block) {
|
||||
NSAssert(NO, @"");
|
||||
return NO;
|
||||
}
|
||||
__block BOOL boolValue = NO;
|
||||
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
if (block(obj)) {
|
||||
boolValue = YES;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return boolValue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
42
Pods/LookinServer/Src/Main/Shared/Category/NSString+Lookin.h
generated
Normal file
42
Pods/LookinServer/Src/Main/Shared/Category/NSString+Lookin.h
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSString+Lookin.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/5/11.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSString (Lookin)
|
||||
|
||||
/**
|
||||
把 CGFloat 转成字符串,最多保留 3 位小数,转换后末尾的 0 会被删除
|
||||
如:1.2341 => @"1.234", 2.1002 => @"2.1", 3.000 => @"3"
|
||||
*/
|
||||
+ (NSString *)lookin_stringFromDouble:(double)doubleValue decimal:(NSUInteger)decimal;
|
||||
|
||||
+ (NSString *)lookin_stringFromRect:(CGRect)rect;
|
||||
|
||||
+ (NSString *)lookin_stringFromInset:(LookinInsets)insets;
|
||||
|
||||
+ (NSString *)lookin_stringFromSize:(CGSize)size;
|
||||
|
||||
+ (NSString *)lookin_stringFromPoint:(CGPoint)point;
|
||||
|
||||
+ (NSString *)lookin_rgbaStringFromColor:(LookinColor *)color;
|
||||
|
||||
- (NSString *)lookin_safeInitWithUTF8String:(const char *)string;
|
||||
|
||||
/// 把 1.2.3 这种 String 版本号转换成数字,可用于大小比较,如 110205 代表 11.2.5 版本
|
||||
- (NSInteger)lookin_numbericOSVersion;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
117
Pods/LookinServer/Src/Main/Shared/Category/NSString+Lookin.m
generated
Normal file
117
Pods/LookinServer/Src/Main/Shared/Category/NSString+Lookin.m
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// NSString+Lookin.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/5/11.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "NSString+Lookin.h"
|
||||
|
||||
@implementation NSString (Lookin)
|
||||
|
||||
+ (NSString *)lookin_stringFromDouble:(double)doubleValue decimal:(NSUInteger)decimal {
|
||||
NSString *formatString = [NSString stringWithFormat:@"%%.%@f", @(decimal)];
|
||||
NSString *string = [NSString stringWithFormat:formatString, doubleValue];
|
||||
for (int i = 0; i < decimal; i++) {
|
||||
if ([[string substringFromIndex:string.length - 1] isEqualToString:@"0"]) {
|
||||
string = [string substringToIndex:string.length - 1];
|
||||
}
|
||||
}
|
||||
if ([[string substringFromIndex:string.length - 1] isEqualToString:@"."]) {
|
||||
string = [string substringToIndex:string.length - 1];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
+ (NSString *)lookin_stringFromInset:(LookinInsets)insets {
|
||||
return [NSString stringWithFormat:@"{%@, %@, %@, %@}",
|
||||
[NSString lookin_stringFromDouble:insets.top decimal:2],
|
||||
[NSString lookin_stringFromDouble:insets.left decimal:2],
|
||||
[NSString lookin_stringFromDouble:insets.bottom decimal:2],
|
||||
[NSString lookin_stringFromDouble:insets.right decimal:2]];
|
||||
}
|
||||
|
||||
+ (NSString *)lookin_stringFromSize:(CGSize)size {
|
||||
return [NSString stringWithFormat:@"{%@, %@}",
|
||||
[NSString lookin_stringFromDouble:size.width decimal:2],
|
||||
[NSString lookin_stringFromDouble:size.height decimal:2]];
|
||||
}
|
||||
|
||||
|
||||
+ (NSString *)lookin_stringFromPoint:(CGPoint)point {
|
||||
return [NSString stringWithFormat:@"{%@, %@}",
|
||||
[NSString lookin_stringFromDouble:point.x decimal:2],
|
||||
[NSString lookin_stringFromDouble:point.y decimal:2]];
|
||||
}
|
||||
|
||||
+ (NSString *)lookin_stringFromRect:(CGRect)rect {
|
||||
return [NSString stringWithFormat:@"{%@, %@, %@, %@}",
|
||||
[NSString lookin_stringFromDouble:rect.origin.x decimal:2],
|
||||
[NSString lookin_stringFromDouble:rect.origin.y decimal:2],
|
||||
[NSString lookin_stringFromDouble:rect.size.width decimal:2],
|
||||
[NSString lookin_stringFromDouble:rect.size.height decimal:2]];
|
||||
}
|
||||
|
||||
+ (NSString *)lookin_rgbaStringFromColor:(LookinColor *)color {
|
||||
if (!color) {
|
||||
return @"nil";
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
UIColor *rgbColor = color;
|
||||
#elif TARGET_OS_MAC
|
||||
NSColor *rgbColor = [color colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
||||
#endif
|
||||
|
||||
CGFloat r, g, b, a;
|
||||
[rgbColor getRed:&r green:&g blue:&b alpha:&a];
|
||||
|
||||
NSString *colorDesc;
|
||||
if (a >= 1) {
|
||||
colorDesc = [NSString stringWithFormat:@"(%.0f, %.0f, %.0f)", r * 255, g * 255, b * 255];
|
||||
} else {
|
||||
colorDesc = [NSString stringWithFormat:@"(%.0f, %.0f, %.0f, %@)", r * 255, g * 255, b * 255, [NSString lookin_stringFromDouble:a decimal:2]];
|
||||
|
||||
}
|
||||
|
||||
return colorDesc;
|
||||
}
|
||||
|
||||
- (NSString *)lookin_safeInitWithUTF8String:(const char *)string {
|
||||
if (NULL != string) {
|
||||
return [self initWithUTF8String:string];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSInteger)lookin_numbericOSVersion {
|
||||
if (self.length == 0) {
|
||||
NSAssert(NO, @"");
|
||||
return 0;
|
||||
}
|
||||
NSArray *versionArr = [self componentsSeparatedByString:@"."];
|
||||
if (versionArr.count != 3) {
|
||||
NSAssert(NO, @"");
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSInteger numbericOSVersion = 0;
|
||||
NSInteger pos = 0;
|
||||
|
||||
while ([versionArr count] > pos && pos < 3) {
|
||||
numbericOSVersion += ([[versionArr objectAtIndex:pos] integerValue] * pow(10, (4 - pos * 2)));
|
||||
pos++;
|
||||
}
|
||||
|
||||
return numbericOSVersion;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
72
Pods/LookinServer/Src/Main/Shared/LookinAppInfo.h
generated
Normal file
72
Pods/LookinServer/Src/Main/Shared/LookinAppInfo.h
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAppInfo.h
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/3.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinAppInfoDevice) {
|
||||
LookinAppInfoDeviceSimulator, // 模拟器
|
||||
LookinAppInfoDeviceIPad, // iPad 真机
|
||||
LookinAppInfoDeviceOthers // 应该视为 iPhone 真机
|
||||
};
|
||||
|
||||
@interface LookinAppInfo : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
/// 每次启动 app 时都会随机生成一个 appInfoIdentifier 直到 app 被 kill 掉
|
||||
@property(nonatomic, assign) NSUInteger appInfoIdentifier;
|
||||
/// mac 端应该先读取该属性,如果为 YES 则表示应该使用之前保存的旧 appInfo 对象即可
|
||||
@property(nonatomic, assign) BOOL shouldUseCache;
|
||||
/// LookinServer 的版本
|
||||
@property(nonatomic, assign) int serverVersion;
|
||||
/// 类似 "1.1.9",只在 1.2.3 以及之后的 LookinServer 版本里有值
|
||||
@property(nonatomic, assign) NSString *serverReadableVersion;
|
||||
/// 如果 iOS 侧使用了 SPM 或引入了 Swift Subspec,则该属性为 1
|
||||
/// 如果 iOS 侧没使用,则该属性为 -1
|
||||
/// 如果不知道,则该属性为 0
|
||||
@property(nonatomic, assign) int swiftEnabledInLookinServer;
|
||||
/// app 的当前截图
|
||||
@property(nonatomic, strong) LookinImage *screenshot;
|
||||
/// 可能为 nil,比如新建的 iOS 空项目
|
||||
@property(nonatomic, strong) LookinImage *appIcon;
|
||||
/// @"微信读书"
|
||||
@property(nonatomic, copy) NSString *appName;
|
||||
/// hughkli.lookin
|
||||
@property(nonatomic, copy) NSString *appBundleIdentifier;
|
||||
/// @"iPhone X"
|
||||
@property(nonatomic, copy) NSString *deviceDescription;
|
||||
/// @"12.1"
|
||||
@property(nonatomic, copy) NSString *osDescription;
|
||||
/// 返回 os 的主版本号,比如 iOS 12.1 的设备将返回 12,iOS 13.2.1 的设备将返回 13
|
||||
@property(nonatomic, assign) NSUInteger osMainVersion;
|
||||
/// 设备类型
|
||||
@property(nonatomic, assign) LookinAppInfoDevice deviceType;
|
||||
/// 屏幕的宽度
|
||||
@property(nonatomic, assign) double screenWidth;
|
||||
/// 屏幕的高度
|
||||
@property(nonatomic, assign) double screenHeight;
|
||||
/// 是几倍的屏幕
|
||||
@property(nonatomic, assign) double screenScale;
|
||||
|
||||
- (BOOL)isEqualToAppInfo:(LookinAppInfo *)info;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
+ (LookinAppInfo *)currentInfoWithScreenshot:(BOOL)hasScreenshot icon:(BOOL)hasIcon localIdentifiers:(NSArray<NSNumber *> *)localIdentifiers;
|
||||
|
||||
#else
|
||||
|
||||
@property(nonatomic, assign) NSTimeInterval cachedTimestamp;
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
242
Pods/LookinServer/Src/Main/Shared/LookinAppInfo.m
generated
Normal file
242
Pods/LookinServer/Src/Main/Shared/LookinAppInfo.m
generated
Normal file
@@ -0,0 +1,242 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAppInfo.m
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/3.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAppInfo.h"
|
||||
#import "LKS_MultiplatformAdapter.h"
|
||||
|
||||
static NSString * const CodingKey_AppIcon = @"1";
|
||||
static NSString * const CodingKey_Screenshot = @"2";
|
||||
static NSString * const CodingKey_DeviceDescription = @"3";
|
||||
static NSString * const CodingKey_OsDescription = @"4";
|
||||
static NSString * const CodingKey_AppName = @"5";
|
||||
static NSString * const CodingKey_ScreenWidth = @"6";
|
||||
static NSString * const CodingKey_ScreenHeight = @"7";
|
||||
static NSString * const CodingKey_DeviceType = @"8";
|
||||
|
||||
@implementation LookinAppInfo
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinAppInfo *newAppInfo = [[LookinAppInfo allocWithZone:zone] init];
|
||||
newAppInfo.appIcon = self.appIcon;
|
||||
newAppInfo.appName = self.appName;
|
||||
newAppInfo.deviceDescription = self.deviceDescription;
|
||||
newAppInfo.osDescription = self.osDescription;
|
||||
newAppInfo.osMainVersion = self.osMainVersion;
|
||||
newAppInfo.deviceType = self.deviceType;
|
||||
newAppInfo.screenWidth = self.screenWidth;
|
||||
newAppInfo.screenHeight = self.screenHeight;
|
||||
newAppInfo.screenScale = self.screenScale;
|
||||
newAppInfo.appInfoIdentifier = self.appInfoIdentifier;
|
||||
return newAppInfo;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
|
||||
self.serverVersion = [aDecoder decodeIntForKey:@"serverVersion"];
|
||||
self.serverReadableVersion = [aDecoder decodeObjectForKey:@"serverReadableVersion"];
|
||||
self.swiftEnabledInLookinServer = [aDecoder decodeIntForKey:@"swiftEnabledInLookinServer"];
|
||||
NSData *screenshotData = [aDecoder decodeObjectForKey:CodingKey_Screenshot];
|
||||
self.screenshot = [[LookinImage alloc] initWithData:screenshotData];
|
||||
|
||||
NSData *appIconData = [aDecoder decodeObjectForKey:CodingKey_AppIcon];
|
||||
self.appIcon = [[LookinImage alloc] initWithData:appIconData];
|
||||
|
||||
self.appName = [aDecoder decodeObjectForKey:CodingKey_AppName];
|
||||
self.appBundleIdentifier = [aDecoder decodeObjectForKey:@"appBundleIdentifier"];
|
||||
self.deviceDescription = [aDecoder decodeObjectForKey:CodingKey_DeviceDescription];
|
||||
self.osDescription = [aDecoder decodeObjectForKey:CodingKey_OsDescription];
|
||||
self.osMainVersion = [aDecoder decodeIntegerForKey:@"osMainVersion"];
|
||||
self.deviceType = [aDecoder decodeIntegerForKey:CodingKey_DeviceType];
|
||||
self.screenWidth = [aDecoder decodeDoubleForKey:CodingKey_ScreenWidth];
|
||||
self.screenHeight = [aDecoder decodeDoubleForKey:CodingKey_ScreenHeight];
|
||||
self.screenScale = [aDecoder decodeDoubleForKey:@"screenScale"];
|
||||
self.appInfoIdentifier = [aDecoder decodeIntegerForKey:@"appInfoIdentifier"];
|
||||
self.shouldUseCache = [aDecoder decodeBoolForKey:@"shouldUseCache"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInt:self.serverVersion forKey:@"serverVersion"];
|
||||
[aCoder encodeObject:self.serverReadableVersion forKey:@"serverReadableVersion"];
|
||||
[aCoder encodeInt:self.swiftEnabledInLookinServer forKey:@"swiftEnabledInLookinServer"];
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
NSData *screenshotData = UIImagePNGRepresentation(self.screenshot);
|
||||
[aCoder encodeObject:screenshotData forKey:CodingKey_Screenshot];
|
||||
|
||||
NSData *appIconData = UIImagePNGRepresentation(self.appIcon);
|
||||
[aCoder encodeObject:appIconData forKey:CodingKey_AppIcon];
|
||||
#elif TARGET_OS_MAC
|
||||
NSData *screenshotData = [self.screenshot TIFFRepresentation];
|
||||
[aCoder encodeObject:screenshotData forKey:CodingKey_Screenshot];
|
||||
|
||||
NSData *appIconData = [self.appIcon TIFFRepresentation];
|
||||
[aCoder encodeObject:appIconData forKey:CodingKey_AppIcon];
|
||||
#endif
|
||||
|
||||
[aCoder encodeObject:self.appName forKey:CodingKey_AppName];
|
||||
[aCoder encodeObject:self.appBundleIdentifier forKey:@"appBundleIdentifier"];
|
||||
[aCoder encodeObject:self.deviceDescription forKey:CodingKey_DeviceDescription];
|
||||
[aCoder encodeObject:self.osDescription forKey:CodingKey_OsDescription];
|
||||
[aCoder encodeInteger:self.osMainVersion forKey:@"osMainVersion"];
|
||||
[aCoder encodeInteger:self.deviceType forKey:CodingKey_DeviceType];
|
||||
[aCoder encodeDouble:self.screenWidth forKey:CodingKey_ScreenWidth];
|
||||
[aCoder encodeDouble:self.screenHeight forKey:CodingKey_ScreenHeight];
|
||||
[aCoder encodeDouble:self.screenScale forKey:@"screenScale"];
|
||||
[aCoder encodeInteger:self.appInfoIdentifier forKey:@"appInfoIdentifier"];
|
||||
[aCoder encodeBool:self.shouldUseCache forKey:@"shouldUseCache"];
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[LookinAppInfo class]]) {
|
||||
return NO;
|
||||
}
|
||||
if ([self isEqualToAppInfo:object]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return self.appName.hash ^ self.deviceDescription.hash ^ self.osDescription.hash ^ self.deviceType;
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToAppInfo:(LookinAppInfo *)info {
|
||||
if (!info) {
|
||||
return NO;
|
||||
}
|
||||
if ([self.appName isEqualToString:info.appName] && [self.deviceDescription isEqualToString:info.deviceDescription] && [self.osDescription isEqualToString:info.osDescription] && self.deviceType == info.deviceType) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
+ (LookinAppInfo *)currentInfoWithScreenshot:(BOOL)hasScreenshot icon:(BOOL)hasIcon localIdentifiers:(NSArray<NSNumber *> *)localIdentifiers {
|
||||
NSInteger selfIdentifier = [self getAppInfoIdentifier];
|
||||
if ([localIdentifiers containsObject:@(selfIdentifier)]) {
|
||||
LookinAppInfo *info = [LookinAppInfo new];
|
||||
info.appInfoIdentifier = selfIdentifier;
|
||||
info.shouldUseCache = YES;
|
||||
return info;
|
||||
}
|
||||
|
||||
LookinAppInfo *info = [[LookinAppInfo alloc] init];
|
||||
info.serverReadableVersion = LOOKIN_SERVER_READABLE_VERSION;
|
||||
#ifdef LOOKIN_SERVER_SWIFT_ENABLED
|
||||
info.swiftEnabledInLookinServer = 1;
|
||||
#else
|
||||
info.swiftEnabledInLookinServer = -1;
|
||||
#endif
|
||||
info.appInfoIdentifier = selfIdentifier;
|
||||
info.appName = [self appName];
|
||||
info.deviceDescription = [UIDevice currentDevice].name;
|
||||
info.appBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
|
||||
if ([self isSimulator]) {
|
||||
info.deviceType = LookinAppInfoDeviceSimulator;
|
||||
} else if ([LKS_MultiplatformAdapter isiPad]) {
|
||||
info.deviceType = LookinAppInfoDeviceIPad;
|
||||
} else {
|
||||
info.deviceType = LookinAppInfoDeviceOthers;
|
||||
}
|
||||
|
||||
info.osDescription = [UIDevice currentDevice].systemVersion;
|
||||
|
||||
NSString *mainVersionStr = [[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."].firstObject;
|
||||
info.osMainVersion = [mainVersionStr integerValue];
|
||||
|
||||
CGSize screenSize = [LKS_MultiplatformAdapter mainScreenBounds].size;
|
||||
info.screenWidth = screenSize.width;
|
||||
info.screenHeight = screenSize.height;
|
||||
info.screenScale = [LKS_MultiplatformAdapter mainScreenScale];
|
||||
|
||||
if (hasScreenshot) {
|
||||
info.screenshot = [self screenshotImage];
|
||||
}
|
||||
if (hasIcon) {
|
||||
info.appIcon = [self appIcon];
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (NSString *)appName {
|
||||
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *displayName = [info objectForKey:@"CFBundleDisplayName"];
|
||||
NSString *name = [info objectForKey:@"CFBundleName"];
|
||||
return displayName.length ? displayName : name;
|
||||
}
|
||||
|
||||
+ (UIImage *)appIcon {
|
||||
#if TARGET_OS_TV
|
||||
return nil;
|
||||
#else
|
||||
NSString *imageName = [[[[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIcons"] objectForKey:@"CFBundlePrimaryIcon"] objectForKey:@"CFBundleIconFiles"] lastObject];
|
||||
if (!imageName.length) {
|
||||
// 正常情况下拿到的 name 可能比如 “AppIcon60x60”。但某些情况可能为 nil,此时直接 return 否则 [UIImage imageNamed:nil] 可能导致 console 报 "CUICatalog: Invalid asset name supplied: '(null)'" 的错误信息
|
||||
return nil;
|
||||
}
|
||||
return [UIImage imageNamed:imageName];
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (UIImage *)screenshotImage {
|
||||
UIWindow *window = [LKS_MultiplatformAdapter keyWindow];
|
||||
if (!window) {
|
||||
return nil;
|
||||
}
|
||||
CGSize size = window.bounds.size;
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
// *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIGraphicsBeginImageContext() failed to allocate CGBitampContext: size={0, 0}, scale=3.000000, bitmapInfo=0x2002. Use UIGraphicsImageRenderer to avoid this assert.'
|
||||
|
||||
// https://github.com/hughkli/Lookin/issues/21
|
||||
return nil;
|
||||
}
|
||||
UIGraphicsBeginImageContextWithOptions(size, YES, 0.4);
|
||||
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (BOOL)isSimulator {
|
||||
if (TARGET_OS_SIMULATOR) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+ (NSInteger)getAppInfoIdentifier {
|
||||
static dispatch_once_t onceToken;
|
||||
static NSInteger identifier = 0;
|
||||
dispatch_once(&onceToken,^{
|
||||
identifier = [[NSDate date] timeIntervalSince1970];
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
257
Pods/LookinServer/Src/Main/Shared/LookinAttrIdentifiers.h
generated
Normal file
257
Pods/LookinServer/Src/Main/Shared/LookinAttrIdentifiers.h
generated
Normal file
@@ -0,0 +1,257 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttrIdentifiers.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/9/18.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma mark - Group
|
||||
|
||||
typedef NSString * LookinAttrGroupIdentifier;
|
||||
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_None;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_Class;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_Relation;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_Layout;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_AutoLayout;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_ViewLayer;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIImageView;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UILabel;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIControl;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIButton;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIScrollView;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UITableView;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UITextView;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UITextField;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIVisualEffectView;
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UIStackView;
|
||||
|
||||
extern LookinAttrGroupIdentifier const LookinAttrGroup_UserCustom;
|
||||
|
||||
#pragma mark - Section
|
||||
|
||||
typedef NSString * LookinAttrSectionIdentifier;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_None;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UserCustom;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Class_Class;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Relation_Relation;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Layout_Frame;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Layout_Bounds;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Layout_SafeArea;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Layout_Position;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_Layout_AnchorPoint;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Hugging;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Resistance;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Constraints;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_IntrinsicSize;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Visibility;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_InterationAndMasks;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Corner;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_BgColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Border;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Shadow;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_ContentMode;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_TintColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Tag;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIImageView_Name;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIImageView_Open;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Text;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Font;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_NumberOfLines;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_TextColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_BreakMode;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Alignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UILabel_CanAdjustFont;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIControl_EnabledSelected;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIControl_VerAlignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIControl_HorAlignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIControl_QMUIOutsideEdge;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIButton_ContentInsets;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIButton_TitleInsets;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIButton_ImageInsets;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentInset;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_AdjustedInset;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_IndicatorInset;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Offset;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentSize;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Behavior;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ShowsIndicator;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Bounce;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ScrollPaging;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentTouches;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Zoom;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_QMUIInitialInset;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_Style;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SectionsNumber;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_RowsNumber;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorStyle;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorInset;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Basic;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Text;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Font;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_TextColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Alignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextView_ContainerInset;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Text;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Placeholder;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Font;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_TextColor;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Alignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Clears;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_CanAdjustFont;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UITextField_ClearButtonMode;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIVisualEffectView_Style;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIVisualEffectView_QMUIForegroundColor;
|
||||
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Axis;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Distribution;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Alignment;
|
||||
extern LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Spacing;
|
||||
|
||||
#pragma mark - Attr
|
||||
|
||||
typedef NSString * LookinAttrIdentifier;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_None;
|
||||
|
||||
/// 用户自定义的
|
||||
extern LookinAttrIdentifier const LookinAttr_UserCustom;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_Class_Class_Class;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_Relation_Relation_Relation;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_Layout_Frame_Frame;
|
||||
extern LookinAttrIdentifier const LookinAttr_Layout_Bounds_Bounds;
|
||||
extern LookinAttrIdentifier const LookinAttr_Layout_SafeArea_SafeArea;
|
||||
extern LookinAttrIdentifier const LookinAttr_Layout_Position_Position;
|
||||
extern LookinAttrIdentifier const LookinAttr_Layout_AnchorPoint_AnchorPoint;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_Hugging_Hor;
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_Hugging_Ver;
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_Resistance_Hor;
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_Resistance_Ver;
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_Constraints_Constraints;
|
||||
extern LookinAttrIdentifier const LookinAttr_AutoLayout_IntrinsicSize_Size;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Visibility_Hidden;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Visibility_Opacity;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_InterationAndMasks_Interaction;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_InterationAndMasks_MasksToBounds;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Corner_Radius;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_BgColor_BgColor;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Border_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Border_Width;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Opacity;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Radius;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_OffsetW;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_OffsetH;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_ContentMode_Mode;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_TintColor_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_TintColor_Mode;
|
||||
extern LookinAttrIdentifier const LookinAttr_ViewLayer_Tag_Tag;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIImageView_Name_Name;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIImageView_Open_Open;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_Text_Text;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_Font_Name;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_Font_Size;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_NumberOfLines_NumberOfLines;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_TextColor_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_Alignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_BreakMode_Mode;
|
||||
extern LookinAttrIdentifier const LookinAttr_UILabel_CanAdjustFont_CanAdjustFont;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIControl_EnabledSelected_Enabled;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIControl_EnabledSelected_Selected;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIControl_VerAlignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIControl_HorAlignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIControl_QMUIOutsideEdge_Edge;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIButton_ContentInsets_Insets;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIButton_TitleInsets_Insets;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIButton_ImageInsets_Insets;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Offset_Offset;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ContentSize_Size;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ContentInset_Inset;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_AdjustedInset_Inset;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Behavior_Behavior;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_IndicatorInset_Inset;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ScrollPaging_ScrollEnabled;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ScrollPaging_PagingEnabled;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Bounce_Ver;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Bounce_Hor;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ShowsIndicator_Hor;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ShowsIndicator_Ver;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ContentTouches_Delay;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_ContentTouches_CanCancel;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_MinScale;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_MaxScale;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_Scale;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_Bounce;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIScrollView_QMUIInitialInset_Inset;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_Style_Style;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_SectionsNumber_Number;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_RowsNumber_Number;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_SeparatorInset_Inset;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_SeparatorColor_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITableView_SeparatorStyle_Style;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Font_Name;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Font_Size;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Basic_Editable;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Basic_Selectable;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Text_Text;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_TextColor_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_Alignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextView_ContainerInset_Inset;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Text_Text;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Placeholder_Placeholder;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Font_Name;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Font_Size;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_TextColor_Color;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Alignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Clears_ClearsOnBeginEditing;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_Clears_ClearsOnInsertion;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_CanAdjustFont_CanAdjustFont;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_CanAdjustFont_MinSize;
|
||||
extern LookinAttrIdentifier const LookinAttr_UITextField_ClearButtonMode_Mode;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIVisualEffectView_Style_Style;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIVisualEffectView_QMUIForegroundColor_Color;
|
||||
|
||||
extern LookinAttrIdentifier const LookinAttr_UIStackView_Axis_Axis;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIStackView_Distribution_Distribution;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIStackView_Alignment_Alignment;
|
||||
extern LookinAttrIdentifier const LookinAttr_UIStackView_Spacing_Spacing;
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
253
Pods/LookinServer/Src/Main/Shared/LookinAttrIdentifiers.m
generated
Normal file
253
Pods/LookinServer/Src/Main/Shared/LookinAttrIdentifiers.m
generated
Normal file
@@ -0,0 +1,253 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttrIdentifiers.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/9/18.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAttrIdentifiers.h"
|
||||
|
||||
// value 不能重复(AppDelegate 里的 runTests 有相关 test)
|
||||
// 如果要去掉某一项可以考虑注释掉而非直接删除,以防止新项和旧项的 value 相同而引发 preference 错乱(这些 value 会被存储到 userDefaults 里)
|
||||
|
||||
#pragma mark - Group
|
||||
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_None = @"n";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_Class = @"c";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_Relation = @"r";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_Layout = @"l";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_AutoLayout = @"a";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_ViewLayer = @"vl";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIImageView = @"i";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UILabel = @"la";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIControl = @"co";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIButton = @"b";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIScrollView = @"s";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UITableView = @"ta";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UITextView = @"te";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UITextField = @"tf";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIVisualEffectView = @"ve";
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UIStackView = @"UIStackView";
|
||||
|
||||
LookinAttrGroupIdentifier const LookinAttrGroup_UserCustom = @"guc"; // user custom
|
||||
|
||||
#pragma mark - Section
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_None = @"n";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UserCustom = @"sec_ctm";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Class_Class = @"cl_c";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Relation_Relation = @"r_r";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Layout_Frame = @"l_f";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Layout_Bounds = @"l_b";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Layout_SafeArea = @"l_s";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Layout_Position = @"l_p";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_Layout_AnchorPoint = @"l_a";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Hugging = @"a_h";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Resistance = @"a_r";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_Constraints = @"a_c";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_AutoLayout_IntrinsicSize = @"a_i";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Visibility = @"v_v";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_InterationAndMasks = @"v_i";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Corner = @"v_c";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_BgColor = @"v_b";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Border = @"v_bo";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Shadow = @"v_s";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_ContentMode = @"v_co";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_TintColor = @"v_t";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_ViewLayer_Tag = @"v_ta";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIImageView_Name = @"i_n";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIImageView_Open = @"i_o";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Text = @"lb_t";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Font = @"lb_f";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_NumberOfLines = @"lb_n";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_TextColor = @"lb_tc";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_BreakMode = @"lb_b";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_Alignment = @"lb_a";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UILabel_CanAdjustFont = @"lb_c";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIControl_EnabledSelected = @"c_e";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIControl_VerAlignment = @"c_v";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIControl_HorAlignment = @"c_h";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIControl_QMUIOutsideEdge = @"c_o";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIButton_ContentInsets = @"b_c";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIButton_TitleInsets = @"b_t";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIButton_ImageInsets = @"b_i";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentInset = @"s_c";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_AdjustedInset = @"s_a";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_IndicatorInset = @"s_i";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Offset = @"s_o";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentSize = @"s_cs";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Behavior = @"s_b";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ShowsIndicator = @"s_si";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Bounce = @"s_bo";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ScrollPaging = @"s_s";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_ContentTouches = @"s_ct";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_Zoom = @"s_z";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIScrollView_QMUIInitialInset = @"s_ii";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_Style = @"t_s";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SectionsNumber = @"t_sn";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_RowsNumber = @"t_r";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorStyle = @"t_ss";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorColor = @"t_sc";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITableView_SeparatorInset = @"t_si";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Basic = @"tv_b";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Text = @"tv_t";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Font = @"tv_f";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_TextColor = @"tv_tc";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_Alignment = @"tv_a";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextView_ContainerInset = @"tv_c";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Text = @"tf_t";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Placeholder = @"tf_p";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Font = @"tf_f";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_TextColor = @"tf_tc";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Alignment = @"tf_a";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_Clears = @"tf_c";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_CanAdjustFont = @"tf_ca";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UITextField_ClearButtonMode = @"tf_cb";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIVisualEffectView_Style = @"ve_s";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIVisualEffectView_QMUIForegroundColor = @"ve_f";
|
||||
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Axis = @"usv_axis";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Distribution = @"usv_dis";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Alignment = @"usv_align";
|
||||
LookinAttrSectionIdentifier const LookinAttrSec_UIStackView_Spacing = @"usv_spa";
|
||||
|
||||
#pragma mark - Attr
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_None = @"n";
|
||||
LookinAttrIdentifier const LookinAttr_UserCustom = @"ctm";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_Class_Class_Class = @"c_c_c";
|
||||
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_Relation_Relation_Relation = @"r_r_r";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_Layout_Frame_Frame = @"l_f_f";
|
||||
LookinAttrIdentifier const LookinAttr_Layout_Bounds_Bounds = @"l_b_b";
|
||||
LookinAttrIdentifier const LookinAttr_Layout_SafeArea_SafeArea = @"l_s_s";
|
||||
LookinAttrIdentifier const LookinAttr_Layout_Position_Position = @"l_p_p";
|
||||
LookinAttrIdentifier const LookinAttr_Layout_AnchorPoint_AnchorPoint = @"l_a_a";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_Hugging_Hor = @"al_h_h";
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_Hugging_Ver = @"al_h_v";
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_Resistance_Hor = @"al_r_h";
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_Resistance_Ver = @"al_r_v";
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_Constraints_Constraints = @"al_c_c";
|
||||
LookinAttrIdentifier const LookinAttr_AutoLayout_IntrinsicSize_Size = @"cl_i_s";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Visibility_Hidden = @"vl_v_h";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Visibility_Opacity = @"vl_v_o";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_InterationAndMasks_Interaction = @"vl_i_i";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_InterationAndMasks_MasksToBounds = @"vl_i_m";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Corner_Radius = @"vl_c_r";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_BgColor_BgColor = @"vl_b_b";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Border_Color = @"vl_b_c";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Border_Width = @"vl_b_w";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Color = @"vl_s_c";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Opacity = @"vl_s_o";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_Radius = @"vl_s_r";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_OffsetW = @"vl_s_ow";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Shadow_OffsetH = @"vl_s_oh";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_ContentMode_Mode = @"vl_c_m";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_TintColor_Color = @"vl_t_c";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_TintColor_Mode = @"vl_t_m";
|
||||
LookinAttrIdentifier const LookinAttr_ViewLayer_Tag_Tag = @"vl_t_t";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIImageView_Name_Name = @"iv_n_n";
|
||||
LookinAttrIdentifier const LookinAttr_UIImageView_Open_Open = @"iv_o_o";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_Text_Text = @"lb_t_t";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_Font_Name = @"lb_f_n";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_Font_Size = @"lb_f_s";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_NumberOfLines_NumberOfLines = @"lb_n_n";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_TextColor_Color = @"lb_t_c";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_Alignment_Alignment = @"lb_a_a";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_BreakMode_Mode = @"lb_b_m";
|
||||
LookinAttrIdentifier const LookinAttr_UILabel_CanAdjustFont_CanAdjustFont = @"lb_c_c";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIControl_EnabledSelected_Enabled = @"ct_e_e";
|
||||
LookinAttrIdentifier const LookinAttr_UIControl_EnabledSelected_Selected = @"ct_e_s";
|
||||
LookinAttrIdentifier const LookinAttr_UIControl_VerAlignment_Alignment = @"ct_v_a";
|
||||
LookinAttrIdentifier const LookinAttr_UIControl_HorAlignment_Alignment = @"ct_h_a";
|
||||
LookinAttrIdentifier const LookinAttr_UIControl_QMUIOutsideEdge_Edge = @"ct_o_e";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIButton_ContentInsets_Insets = @"bt_c_i";
|
||||
LookinAttrIdentifier const LookinAttr_UIButton_TitleInsets_Insets = @"bt_t_i";
|
||||
LookinAttrIdentifier const LookinAttr_UIButton_ImageInsets_Insets = @"bt_i_i";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Offset_Offset = @"sv_o_o";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ContentSize_Size = @"sv_c_s";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ContentInset_Inset = @"sv_c_i";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_AdjustedInset_Inset = @"sv_a_i";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Behavior_Behavior = @"sv_b_b";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_IndicatorInset_Inset = @"sv_i_i";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ScrollPaging_ScrollEnabled = @"sv_s_s";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ScrollPaging_PagingEnabled = @"sv_s_p";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Bounce_Ver = @"sv_b_v";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Bounce_Hor = @"sv_b_h";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ShowsIndicator_Hor = @"sv_h_h";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ShowsIndicator_Ver = @"sv_s_v";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ContentTouches_Delay = @"sv_c_d";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_ContentTouches_CanCancel = @"sv_c_c";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_MinScale = @"sv_z_mi";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_MaxScale = @"sv_z_ma";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_Scale = @"sv_z_s";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_Zoom_Bounce = @"sv_z_b";
|
||||
LookinAttrIdentifier const LookinAttr_UIScrollView_QMUIInitialInset_Inset = @"sv_qi_i";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_Style_Style = @"tv_s_s";
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_SectionsNumber_Number = @"tv_s_n";
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_RowsNumber_Number = @"tv_r_n";
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_SeparatorInset_Inset = @"tv_s_i";
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_SeparatorColor_Color = @"tv_s_c";
|
||||
LookinAttrIdentifier const LookinAttr_UITableView_SeparatorStyle_Style = @"tv_ss_s";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Font_Name = @"te_f_n";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Font_Size = @"te_f_s";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Basic_Editable = @"te_b_e";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Basic_Selectable = @"te_b_s";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Text_Text = @"te_t_t";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_TextColor_Color = @"te_t_c";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_Alignment_Alignment = @"te_a_a";
|
||||
LookinAttrIdentifier const LookinAttr_UITextView_ContainerInset_Inset = @"te_c_i";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Text_Text = @"tf_t_t";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Placeholder_Placeholder = @"tf_p_p";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Font_Name = @"tf_f_n";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Font_Size = @"tf_f_s";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_TextColor_Color = @"tf_t_c";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Alignment_Alignment = @"tf_a_a";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Clears_ClearsOnBeginEditing = @"tf_c_c";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_Clears_ClearsOnInsertion = @"tf_c_co";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_CanAdjustFont_CanAdjustFont = @"tf_c_ca";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_CanAdjustFont_MinSize = @"tf_c_m";
|
||||
LookinAttrIdentifier const LookinAttr_UITextField_ClearButtonMode_Mode = @"tf_cb_m";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIVisualEffectView_Style_Style = @"ve_s_s";
|
||||
LookinAttrIdentifier const LookinAttr_UIVisualEffectView_QMUIForegroundColor_Color = @"ve_f_c";
|
||||
|
||||
LookinAttrIdentifier const LookinAttr_UIStackView_Axis_Axis = @"usv_axis_axis";
|
||||
LookinAttrIdentifier const LookinAttr_UIStackView_Distribution_Distribution = @"usv_dis_dis";
|
||||
LookinAttrIdentifier const LookinAttr_UIStackView_Alignment_Alignment = @"usv_ali_ali";
|
||||
LookinAttrIdentifier const LookinAttr_UIStackView_Spacing_Spacing = @"usv_spa_spa";
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
50
Pods/LookinServer/Src/Main/Shared/LookinAttrType.h
generated
Normal file
50
Pods/LookinServer/Src/Main/Shared/LookinAttrType.h
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttrIdentifiers.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/12/1.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
/// 注意:新属性只能加到末尾,否则新旧版本搭配时可能有兼容问题
|
||||
typedef NS_ENUM(NSInteger, LookinAttrType) {
|
||||
LookinAttrTypeNone,
|
||||
LookinAttrTypeVoid,
|
||||
LookinAttrTypeChar,
|
||||
LookinAttrTypeInt,
|
||||
LookinAttrTypeShort,
|
||||
LookinAttrTypeLong,
|
||||
LookinAttrTypeLongLong,
|
||||
LookinAttrTypeUnsignedChar,
|
||||
LookinAttrTypeUnsignedInt,
|
||||
LookinAttrTypeUnsignedShort,
|
||||
LookinAttrTypeUnsignedLong,
|
||||
LookinAttrTypeUnsignedLongLong,
|
||||
LookinAttrTypeFloat,
|
||||
LookinAttrTypeDouble,
|
||||
LookinAttrTypeBOOL,
|
||||
LookinAttrTypeSel,
|
||||
LookinAttrTypeClass,
|
||||
LookinAttrTypeCGPoint,
|
||||
LookinAttrTypeCGVector,
|
||||
LookinAttrTypeCGSize,
|
||||
LookinAttrTypeCGRect,
|
||||
LookinAttrTypeCGAffineTransform,
|
||||
LookinAttrTypeUIEdgeInsets,
|
||||
LookinAttrTypeUIOffset,
|
||||
LookinAttrTypeNSString,
|
||||
LookinAttrTypeEnumInt,
|
||||
LookinAttrTypeEnumLong,
|
||||
/// value 实际为 RGBA 数组,即 @[NSNumber, NSNumber, NSNumber, NSNumber],NSNumber 范围是 0 ~ 1
|
||||
LookinAttrTypeUIColor,
|
||||
/// 业务需要根据具体的 AttrIdentifier 来解析
|
||||
LookinAttrTypeCustomObj,
|
||||
|
||||
LookinAttrTypeEnumString,
|
||||
LookinAttrTypeShadow,
|
||||
LookinAttrTypeJson
|
||||
};
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
48
Pods/LookinServer/Src/Main/Shared/LookinAttribute.h
generated
Normal file
48
Pods/LookinServer/Src/Main/Shared/LookinAttribute.h
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttribute.h
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/17.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LookinAttrIdentifiers.h"
|
||||
#import "LookinCodingValueType.h"
|
||||
#import "LookinAttrType.h"
|
||||
|
||||
@class LookinDisplayItem;
|
||||
|
||||
@interface LookinAttribute : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
@property(nonatomic, copy) LookinAttrIdentifier identifier;
|
||||
|
||||
/// 只有 Custom Attr 才有该属性
|
||||
@property(nonatomic, copy) NSString *displayTitle;
|
||||
|
||||
/// 标识 value 的具体类型(如 double / NSString /...)
|
||||
@property(nonatomic, assign) LookinAttrType attrType;
|
||||
|
||||
/// 具体的值,需配合 attrType 属性来解析它
|
||||
/// 对于 String、Color 等 attyType,该属性可能为 nil
|
||||
@property(nonatomic, strong) id value;
|
||||
|
||||
/// 额外信息,大部分情况下它是 nil
|
||||
/// 当 attyType 为 LookinAttrTypeEnumString 时,extraValue 是一个 [String] 且保存了 allEnumCases
|
||||
@property(nonatomic, strong) id extraValue;
|
||||
|
||||
/// 仅 Custom Attr 可能有该属性
|
||||
/// 对于有 retainedSetter 的 Custom Attr,它的 setter 会以 customSetterID 作为 key 被保存到 LKS_CustomAttrSetterManager 里,后续可以通过这个 uniqueID 重新把 setter 从 LKS_CustomAttrSetterManager 里取出来并调用
|
||||
@property(nonatomic, copy) NSString *customSetterID;
|
||||
|
||||
#pragma mark - 以下属性不会参与 encode/decode
|
||||
|
||||
/// 标识该 LookinAttribute 对象隶属于哪一个 LookinDisplayItem
|
||||
@property(nonatomic, weak) LookinDisplayItem *targetDisplayItem;
|
||||
|
||||
- (BOOL)isUserCustom;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
64
Pods/LookinServer/Src/Main/Shared/LookinAttribute.m
generated
Normal file
64
Pods/LookinServer/Src/Main/Shared/LookinAttribute.m
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttribute.m
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/17.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAttribute.h"
|
||||
#import "LookinDisplayItem.h"
|
||||
|
||||
@implementation LookinAttribute
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinAttribute *newAttr = [[LookinAttribute allocWithZone:zone] init];
|
||||
newAttr.identifier = self.identifier;
|
||||
newAttr.displayTitle = self.displayTitle;
|
||||
newAttr.value = self.value;
|
||||
newAttr.attrType = self.attrType;
|
||||
newAttr.extraValue = self.extraValue;
|
||||
newAttr.customSetterID = self.customSetterID;
|
||||
return newAttr;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.displayTitle forKey:@"displayTitle"];
|
||||
[aCoder encodeObject:self.identifier forKey:@"identifier"];
|
||||
[aCoder encodeInteger:self.attrType forKey:@"attrType"];
|
||||
[aCoder encodeObject:self.value forKey:@"value"];
|
||||
[aCoder encodeObject:self.extraValue forKey:@"extraValue"];
|
||||
[aCoder encodeObject:self.customSetterID forKey:@"customSetterID"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.displayTitle = [aDecoder decodeObjectForKey:@"displayTitle"];
|
||||
self.identifier = [aDecoder decodeObjectForKey:@"identifier"];
|
||||
self.attrType = [aDecoder decodeIntegerForKey:@"attrType"];
|
||||
self.value = [aDecoder decodeObjectForKey:@"value"];
|
||||
self.extraValue = [aDecoder decodeObjectForKey:@"extraValue"];
|
||||
self.customSetterID = [aDecoder decodeObjectForKey:@"customSetterID"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isUserCustom {
|
||||
return [self.identifier isEqualToString:LookinAttr_UserCustom];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
31
Pods/LookinServer/Src/Main/Shared/LookinAttributeModification.h
generated
Normal file
31
Pods/LookinServer/Src/Main/Shared/LookinAttributeModification.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributeModification.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/11/20.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinAttrType.h"
|
||||
|
||||
@interface LookinAttributeModification : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) unsigned long targetOid;
|
||||
|
||||
@property(nonatomic, assign) SEL setterSelector;
|
||||
@property(nonatomic, assign) SEL getterSelector;
|
||||
|
||||
@property(nonatomic, assign) LookinAttrType attrType;
|
||||
@property(nonatomic, strong) id value;
|
||||
|
||||
/// 1.0.4 开始加入这个参数
|
||||
@property(nonatomic, copy) NSString *clientReadableVersion;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
40
Pods/LookinServer/Src/Main/Shared/LookinAttributeModification.m
generated
Normal file
40
Pods/LookinServer/Src/Main/Shared/LookinAttributeModification.m
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributeModification.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/11/20.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinAttributeModification.h"
|
||||
|
||||
@implementation LookinAttributeModification
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:@(self.targetOid) forKey:@"targetOid"];
|
||||
[aCoder encodeObject:NSStringFromSelector(self.setterSelector) forKey:@"setterSelector"];
|
||||
[aCoder encodeInteger:self.attrType forKey:@"attrType"];
|
||||
[aCoder encodeObject:self.value forKey:@"value"];
|
||||
[aCoder encodeObject:self.clientReadableVersion forKey:@"clientReadableVersion"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.targetOid = [[aDecoder decodeObjectForKey:@"targetOid"] unsignedLongValue];
|
||||
self.setterSelector = NSSelectorFromString([aDecoder decodeObjectForKey:@"setterSelector"]);
|
||||
self.attrType = [aDecoder decodeIntegerForKey:@"attrType"];
|
||||
self.value = [aDecoder decodeObjectForKey:@"value"];
|
||||
self.clientReadableVersion = [aDecoder decodeObjectForKey:@"clientReadableVersion"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
41
Pods/LookinServer/Src/Main/Shared/LookinAttributesGroup.h
generated
Normal file
41
Pods/LookinServer/Src/Main/Shared/LookinAttributesGroup.h
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributesGroup.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/11/19.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinAttrIdentifiers.h"
|
||||
|
||||
@class LookinAttributesSection;
|
||||
|
||||
/**
|
||||
In Lookin, a LookinAttributesGroup instance will be rendered as a property card.
|
||||
|
||||
When isUserCustom is false: two LookinAttributesGroup instances will be regard as equal when they has the same LookinAttrGroupIdentifier.
|
||||
When isUserCustom is true: two LookinAttributesGroup instances will be regard as equal when they has the same title.
|
||||
当 isUserCustom 为 false 时:若两个 attrGroup 有相同的 LookinAttrGroupIdentifier,则 isEqual: 返回 YES
|
||||
*/
|
||||
@interface LookinAttributesGroup : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
/// 只有在 identifier 为 custom 时,才存在该值
|
||||
@property(nonatomic, copy) NSString *userCustomTitle;
|
||||
|
||||
@property(nonatomic, copy) LookinAttrGroupIdentifier identifier;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinAttributesSection *> *attrSections;
|
||||
|
||||
/// 如果是 custom 则返回 userCustomTitle,如果不是 custom 则返回 identifier
|
||||
- (NSString *)uniqueKey;
|
||||
|
||||
- (BOOL)isUserCustom;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
92
Pods/LookinServer/Src/Main/Shared/LookinAttributesGroup.m
generated
Normal file
92
Pods/LookinServer/Src/Main/Shared/LookinAttributesGroup.m
generated
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributesGroup.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/11/19.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAttributesGroup.h"
|
||||
#import "LookinAttribute.h"
|
||||
#import "LookinAttributesSection.h"
|
||||
#import "LookinDashboardBlueprint.h"
|
||||
#import "NSArray+Lookin.h"
|
||||
|
||||
@implementation LookinAttributesGroup
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinAttributesGroup *newGroup = [[LookinAttributesGroup allocWithZone:zone] init];
|
||||
newGroup.userCustomTitle = self.userCustomTitle;
|
||||
newGroup.identifier = self.identifier;
|
||||
newGroup.attrSections = [self.attrSections lookin_map:^id(NSUInteger idx, LookinAttributesSection *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.userCustomTitle forKey:@"userCustomTitle"];
|
||||
[aCoder encodeObject:self.identifier forKey:@"identifier"];
|
||||
[aCoder encodeObject:self.attrSections forKey:@"attrSections"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.userCustomTitle = [aDecoder decodeObjectForKey:@"userCustomTitle"];
|
||||
self.identifier = [aDecoder decodeObjectForKey:@"identifier"];
|
||||
self.attrSections = [aDecoder decodeObjectForKey:@"attrSections"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return self.uniqueKey.hash;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[LookinAttributesGroup class]]) {
|
||||
return NO;
|
||||
}
|
||||
LookinAttributesGroup *targetObject = object;
|
||||
|
||||
if (![self.identifier isEqualToString:targetObject.identifier]) {
|
||||
return false;
|
||||
}
|
||||
if ([self.identifier isEqualToString:LookinAttrGroup_UserCustom]) {
|
||||
BOOL ret = [self.userCustomTitle isEqualToString:targetObject.userCustomTitle];
|
||||
return ret;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)uniqueKey {
|
||||
if ([self.identifier isEqualToString:LookinAttrGroup_UserCustom]) {
|
||||
return self.userCustomTitle;
|
||||
} else {
|
||||
return self.identifier;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isUserCustom {
|
||||
return [self.identifier isEqualToString:LookinAttrSec_UserCustom];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
35
Pods/LookinServer/Src/Main/Shared/LookinAttributesSection.h
generated
Normal file
35
Pods/LookinServer/Src/Main/Shared/LookinAttributesSection.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributesSection.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/3/2.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinAttrIdentifiers.h"
|
||||
|
||||
@class LookinAttribute;
|
||||
|
||||
typedef NS_ENUM (NSInteger, LookinAttributesSectionStyle) {
|
||||
LookinAttributesSectionStyleDefault, // 每个 attr 独占一行
|
||||
LookinAttributesSectionStyle0, // frame 等卡片使用,前 4 个 attr 每行两个,之后每个 attr 在同一排,每个宽度为 1/4
|
||||
LookinAttributesSectionStyle1, // 第一个 attr 在第一排靠左,第二个 attr 在第一排靠右,之后的 attr 每个独占一行
|
||||
LookinAttributesSectionStyle2 // 第一排独占一行,剩下的在同一行且均分宽度
|
||||
};
|
||||
|
||||
@interface LookinAttributesSection : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
@property(nonatomic, copy) LookinAttrSectionIdentifier identifier;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinAttribute *> *attributes;
|
||||
|
||||
- (BOOL)isUserCustom;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
56
Pods/LookinServer/Src/Main/Shared/LookinAttributesSection.m
generated
Normal file
56
Pods/LookinServer/Src/Main/Shared/LookinAttributesSection.m
generated
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAttributesSection.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/3/2.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAttributesSection.h"
|
||||
#import "LookinAttribute.h"
|
||||
|
||||
#import "NSArray+Lookin.h"
|
||||
|
||||
@implementation LookinAttributesSection
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinAttributesSection *newSection = [[LookinAttributesSection allocWithZone:zone] init];
|
||||
newSection.identifier = self.identifier;
|
||||
newSection.attributes = [self.attributes lookin_map:^id(NSUInteger idx, LookinAttribute *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
return newSection;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.identifier forKey:@"identifier"];
|
||||
[aCoder encodeObject:self.attributes forKey:@"attributes"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.identifier = [aDecoder decodeObjectForKey:@"identifier"];
|
||||
self.attributes = [aDecoder decodeObjectForKey:@"attributes"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isUserCustom {
|
||||
return [self.identifier isEqualToString:LookinAttrSec_UserCustom];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
51
Pods/LookinServer/Src/Main/Shared/LookinAutoLayoutConstraint.h
generated
Normal file
51
Pods/LookinServer/Src/Main/Shared/LookinAutoLayoutConstraint.h
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAutoLayoutConstraint.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/9/28.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
@class LookinObject;
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinConstraintItemType) {
|
||||
LookinConstraintItemTypeUnknown,
|
||||
LookinConstraintItemTypeNil,
|
||||
LookinConstraintItemTypeView,
|
||||
LookinConstraintItemTypeSelf,
|
||||
LookinConstraintItemTypeSuper,
|
||||
LookinConstraintItemTypeLayoutGuide
|
||||
};
|
||||
|
||||
@interface LookinAutoLayoutConstraint : NSObject <NSSecureCoding>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
+ (instancetype)instanceFromNSConstraint:(NSLayoutConstraint *)constraint isEffective:(BOOL)isEffective firstItemType:(LookinConstraintItemType)firstItemType secondItemType:(LookinConstraintItemType)secondItemType;
|
||||
#endif
|
||||
|
||||
@property(nonatomic, assign) BOOL effective;
|
||||
@property(nonatomic, assign) BOOL active;
|
||||
@property(nonatomic, assign) BOOL shouldBeArchived;
|
||||
@property(nonatomic, strong) LookinObject *firstItem;
|
||||
@property(nonatomic, assign) LookinConstraintItemType firstItemType;
|
||||
/// iOS 里的 NSLayoutAttribute,注意 iOS 和 macOS 虽然都有 NSLayoutAttribute 但是 value 非常不同,因此这里使用 NSInteger 避免混淆
|
||||
@property(nonatomic, assign) NSInteger firstAttribute;
|
||||
@property(nonatomic, assign) NSLayoutRelation relation;
|
||||
@property(nonatomic, strong) LookinObject *secondItem;
|
||||
@property(nonatomic, assign) LookinConstraintItemType secondItemType;
|
||||
/// iOS 里的 NSLayoutAttribute,注意 iOS 和 macOS 虽然都有 NSLayoutAttribute 但是 value 非常不同,因此这里使用 NSInteger 避免混淆
|
||||
@property(nonatomic, assign) NSInteger secondAttribute;
|
||||
@property(nonatomic, assign) CGFloat multiplier;
|
||||
@property(nonatomic, assign) CGFloat constant;
|
||||
@property(nonatomic, assign) CGFloat priority;
|
||||
@property(nonatomic, copy) NSString *identifier;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
107
Pods/LookinServer/Src/Main/Shared/LookinAutoLayoutConstraint.m
generated
Normal file
107
Pods/LookinServer/Src/Main/Shared/LookinAutoLayoutConstraint.m
generated
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinAutoLayoutConstraint.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/9/28.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinAutoLayoutConstraint.h"
|
||||
#import "LookinObject.h"
|
||||
|
||||
@implementation LookinAutoLayoutConstraint
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
+ (instancetype)instanceFromNSConstraint:(NSLayoutConstraint *)constraint isEffective:(BOOL)isEffective firstItemType:(LookinConstraintItemType)firstItemType secondItemType:(LookinConstraintItemType)secondItemType {
|
||||
LookinAutoLayoutConstraint *instance = [LookinAutoLayoutConstraint new];
|
||||
instance.effective = isEffective;
|
||||
instance.active = constraint.active;
|
||||
instance.shouldBeArchived = constraint.shouldBeArchived;
|
||||
instance.firstItem = [LookinObject instanceWithObject:constraint.firstItem];
|
||||
instance.firstItemType = firstItemType;
|
||||
instance.firstAttribute = constraint.firstAttribute;
|
||||
instance.relation = constraint.relation;
|
||||
instance.secondItem = [LookinObject instanceWithObject:constraint.secondItem];
|
||||
instance.secondItemType = secondItemType;
|
||||
instance.secondAttribute = constraint.secondAttribute;
|
||||
instance.multiplier = constraint.multiplier;
|
||||
instance.constant = constraint.constant;
|
||||
instance.priority = constraint.priority;
|
||||
instance.identifier = constraint.identifier;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)setFirstAttribute:(NSInteger)firstAttribute {
|
||||
_firstAttribute = firstAttribute;
|
||||
[self _assertUnknownAttribute:firstAttribute];
|
||||
}
|
||||
|
||||
- (void)setSecondAttribute:(NSInteger)secondAttribute {
|
||||
_secondAttribute = secondAttribute;
|
||||
[self _assertUnknownAttribute:secondAttribute];
|
||||
}
|
||||
|
||||
- (void)_assertUnknownAttribute:(NSInteger)attribute {
|
||||
// 以下几个 assert 用来帮助发现那些系统私有的定义,正式发布时应该去掉这几个 assert
|
||||
if (attribute > 20 && attribute < 32) {
|
||||
NSAssert(NO, nil);
|
||||
}
|
||||
if (attribute > 37) {
|
||||
NSAssert(NO, nil);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark - <NSSecureCoding>
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeBool:self.effective forKey:@"effective"];
|
||||
[aCoder encodeBool:self.active forKey:@"active"];
|
||||
[aCoder encodeBool:self.shouldBeArchived forKey:@"shouldBeArchived"];
|
||||
[aCoder encodeObject:self.firstItem forKey:@"firstItem"];
|
||||
[aCoder encodeInteger:self.firstItemType forKey:@"firstItemType"];
|
||||
[aCoder encodeInteger:self.firstAttribute forKey:@"firstAttribute"];
|
||||
[aCoder encodeInteger:self.relation forKey:@"relation"];
|
||||
[aCoder encodeObject:self.secondItem forKey:@"secondItem"];
|
||||
[aCoder encodeInteger:self.secondItemType forKey:@"secondItemType"];
|
||||
[aCoder encodeInteger:self.secondAttribute forKey:@"secondAttribute"];
|
||||
[aCoder encodeDouble:self.multiplier forKey:@"multiplier"];
|
||||
[aCoder encodeDouble:self.constant forKey:@"constant"];
|
||||
[aCoder encodeDouble:self.priority forKey:@"priority"];
|
||||
[aCoder encodeObject:self.identifier forKey:@"identifier"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.effective = [aDecoder decodeBoolForKey:@"effective"];
|
||||
self.active = [aDecoder decodeBoolForKey:@"active"];
|
||||
self.shouldBeArchived = [aDecoder decodeBoolForKey:@"shouldBeArchived"];
|
||||
self.firstItem = [aDecoder decodeObjectForKey:@"firstItem"];
|
||||
self.firstItemType = [aDecoder decodeIntegerForKey:@"firstItemType"];
|
||||
self.firstAttribute = [aDecoder decodeIntegerForKey:@"firstAttribute"];
|
||||
self.relation = [aDecoder decodeIntegerForKey:@"relation"];
|
||||
self.secondItem = [aDecoder decodeObjectForKey:@"secondItem"];
|
||||
self.secondItemType = [aDecoder decodeIntegerForKey:@"secondItemType"];
|
||||
self.secondAttribute = [aDecoder decodeIntegerForKey:@"secondAttribute"];
|
||||
self.multiplier = [aDecoder decodeDoubleForKey:@"multiplier"];
|
||||
self.constant = [aDecoder decodeDoubleForKey:@"constant"];
|
||||
self.priority = [aDecoder decodeDoubleForKey:@"priority"];
|
||||
self.identifier = [aDecoder decodeObjectForKey:@"identifier"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
30
Pods/LookinServer/Src/Main/Shared/LookinCodingValueType.h
generated
Normal file
30
Pods/LookinServer/Src/Main/Shared/LookinCodingValueType.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinCodingValueType.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/2/13.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinCodingValueType) {
|
||||
LookinCodingValueTypeUnknown,
|
||||
LookinCodingValueTypeChar,
|
||||
LookinCodingValueTypeDouble,
|
||||
LookinCodingValueTypeFloat,
|
||||
LookinCodingValueTypeLongLong,
|
||||
// LookinCodingValueTypePoint,
|
||||
// LookinCodingValueTypeString,
|
||||
// LookinCodingValueTypeStringArray,
|
||||
// LookinCodingValueTypeEdgeInsets,
|
||||
// LookinCodingValueTypeRect,
|
||||
LookinCodingValueTypeBOOL,
|
||||
// LookinCodingValueTypeSize,
|
||||
LookinCodingValueTypeColor,
|
||||
LookinCodingValueTypeEnum,
|
||||
// LookinCodingValueTypeRange,
|
||||
LookinCodingValueTypeImage
|
||||
};
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
24
Pods/LookinServer/Src/Main/Shared/LookinConnectionAttachment.h
generated
Normal file
24
Pods/LookinServer/Src/Main/Shared/LookinConnectionAttachment.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinConnectionAttachment.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/2/15.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinCodingValueType.h"
|
||||
|
||||
@interface LookinConnectionAttachment : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) LookinCodingValueType dataType;
|
||||
|
||||
@property(nonatomic, strong) id data;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
52
Pods/LookinServer/Src/Main/Shared/LookinConnectionAttachment.m
generated
Normal file
52
Pods/LookinServer/Src/Main/Shared/LookinConnectionAttachment.m
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinConnectionAttachment.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/2/15.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinConnectionAttachment.h"
|
||||
#import "LookinDefines.h"
|
||||
#import "NSObject+Lookin.h"
|
||||
|
||||
static NSString * const Key_Data = @"0";
|
||||
static NSString * const Key_DataType = @"1";
|
||||
|
||||
@interface LookinConnectionAttachment ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation LookinConnectionAttachment
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
|
||||
[aCoder encodeObject:[self.data lookin_encodedObjectWithType:self.dataType] forKey:Key_Data];
|
||||
[aCoder encodeInteger:self.dataType forKey:Key_DataType];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.dataType = [aDecoder decodeIntegerForKey:Key_DataType];
|
||||
self.data = [[aDecoder decodeObjectForKey:Key_Data] lookin_decodedObjectWithType:self.dataType];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
36
Pods/LookinServer/Src/Main/Shared/LookinConnectionResponseAttachment.h
generated
Normal file
36
Pods/LookinServer/Src/Main/Shared/LookinConnectionResponseAttachment.h
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinConnectionResponse.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/1/15.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinConnectionAttachment.h"
|
||||
|
||||
@interface LookinConnectionResponseAttachment : LookinConnectionAttachment
|
||||
|
||||
+ (instancetype)attachmentWithError:(NSError *)error;
|
||||
|
||||
@property(nonatomic, assign) int lookinServerVersion;
|
||||
|
||||
@property(nonatomic, strong) NSError *error;
|
||||
|
||||
/// 如果为 YES,则表示 app 正处于后台模式,默认为 NO
|
||||
@property(nonatomic, assign) BOOL appIsInBackground;
|
||||
|
||||
/**
|
||||
dataTotalCount 为 0 时表示仅有这一个 response,默认为 0
|
||||
dataTotalCount 大于 0 时表示可能有多个 response,当所有 response 的 currentDataCount 的总和大于 dataTotalCount 即表示所有 response 已接收完毕
|
||||
*/
|
||||
@property(nonatomic, assign) NSUInteger dataTotalCount;
|
||||
@property(nonatomic, assign) NSUInteger currentDataCount;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
62
Pods/LookinServer/Src/Main/Shared/LookinConnectionResponseAttachment.m
generated
Normal file
62
Pods/LookinServer/Src/Main/Shared/LookinConnectionResponseAttachment.m
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinConnectionResponse.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/1/15.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinConnectionResponseAttachment.h"
|
||||
#import "LookinDefines.h"
|
||||
|
||||
@interface LookinConnectionResponseAttachment ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation LookinConnectionResponseAttachment
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeInt:self.lookinServerVersion forKey:@"lookinServerVersion"];
|
||||
[aCoder encodeObject:self.error forKey:@"error"];
|
||||
[aCoder encodeObject:@(self.dataTotalCount) forKey:@"dataTotalCount"];
|
||||
[aCoder encodeObject:@(self.currentDataCount) forKey:@"currentDataCount"];
|
||||
[aCoder encodeBool:self.appIsInBackground forKey:@"appIsInBackground"];
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.lookinServerVersion = LOOKIN_SERVER_VERSION;
|
||||
self.dataTotalCount = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
self.lookinServerVersion = [aDecoder decodeIntForKey:@"lookinServerVersion"];
|
||||
self.error = [aDecoder decodeObjectForKey:@"error"];
|
||||
self.dataTotalCount = [[aDecoder decodeObjectForKey:@"dataTotalCount"] unsignedIntegerValue];
|
||||
self.currentDataCount = [[aDecoder decodeObjectForKey:@"currentDataCount"] unsignedIntegerValue];
|
||||
self.appIsInBackground = [aDecoder decodeBoolForKey:@"appIsInBackground"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (instancetype)attachmentWithError:(NSError *)error {
|
||||
LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new];
|
||||
attachment.error = error;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
20
Pods/LookinServer/Src/Main/Shared/LookinCustomAttrModification.h
generated
Normal file
20
Pods/LookinServer/Src/Main/Shared/LookinCustomAttrModification.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
//
|
||||
// LookinCustomAttrModification.h
|
||||
// LookinShared
|
||||
//
|
||||
// Created by likaimacbookhome on 2023/11/4.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinAttrType.h"
|
||||
|
||||
@interface LookinCustomAttrModification : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) LookinAttrType attrType;
|
||||
@property(nonatomic, copy) NSString *customSetterID;
|
||||
@property(nonatomic, strong) id value;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
34
Pods/LookinServer/Src/Main/Shared/LookinCustomAttrModification.m
generated
Normal file
34
Pods/LookinServer/Src/Main/Shared/LookinCustomAttrModification.m
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
//
|
||||
// LookinCustomAttrModification.m
|
||||
// LookinShared
|
||||
//
|
||||
// Created by likaimacbookhome on 2023/11/4.
|
||||
//
|
||||
|
||||
#import "LookinCustomAttrModification.h"
|
||||
|
||||
@implementation LookinCustomAttrModification
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:self.attrType forKey:@"attrType"];
|
||||
[aCoder encodeObject:self.value forKey:@"value"];
|
||||
[aCoder encodeObject:self.customSetterID forKey:@"customSetterID"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.attrType = [aDecoder decodeIntegerForKey:@"attrType"];
|
||||
self.value = [aDecoder decodeObjectForKey:@"value"];
|
||||
self.customSetterID = [aDecoder decodeObjectForKey:@"customSetterID"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
21
Pods/LookinServer/Src/Main/Shared/LookinCustomDisplayItemInfo.h
generated
Normal file
21
Pods/LookinServer/Src/Main/Shared/LookinCustomDisplayItemInfo.h
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
//
|
||||
// LookinCustomDisplayItemInfo.h
|
||||
// LookinServer
|
||||
//
|
||||
// Created by likai.123 on 2023/11/1.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LookinCustomDisplayItemInfo : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
/// 该属性可能有值(CGRect)也可能是 nil(nil 时则表示无图像)
|
||||
@property(nonatomic, strong) NSValue *frameInWindow;
|
||||
@property(nonatomic, copy) NSString *title;
|
||||
@property(nonatomic, copy) NSString *subtitle;
|
||||
@property(nonatomic, copy) NSString *danceuiSource;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
59
Pods/LookinServer/Src/Main/Shared/LookinCustomDisplayItemInfo.m
generated
Normal file
59
Pods/LookinServer/Src/Main/Shared/LookinCustomDisplayItemInfo.m
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinCustomDisplayItemInfo.m
|
||||
// LookinServer
|
||||
//
|
||||
// Created by likai.123 on 2023/11/1.
|
||||
//
|
||||
|
||||
#import "LookinCustomDisplayItemInfo.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
@implementation LookinCustomDisplayItemInfo
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinCustomDisplayItemInfo *newInstance = [[LookinCustomDisplayItemInfo allocWithZone:zone] init];
|
||||
|
||||
if (self.frameInWindow) {
|
||||
#if TARGET_OS_IPHONE
|
||||
CGRect rect = [self.frameInWindow CGRectValue];
|
||||
newInstance.frameInWindow = [NSValue valueWithCGRect:rect];
|
||||
#elif TARGET_OS_MAC
|
||||
CGRect rect = [self.frameInWindow rectValue];
|
||||
newInstance.frameInWindow = [NSValue valueWithRect:rect];
|
||||
#endif
|
||||
}
|
||||
newInstance.title = self.title;
|
||||
newInstance.subtitle = self.subtitle;
|
||||
newInstance.danceuiSource = self.danceuiSource;
|
||||
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.frameInWindow forKey:@"frameInWindow"];
|
||||
[aCoder encodeObject:self.title forKey:@"title"];
|
||||
[aCoder encodeObject:self.subtitle forKey:@"subtitle"];
|
||||
[aCoder encodeObject:self.danceuiSource forKey:@"danceuiSource"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.frameInWindow = [aDecoder decodeObjectForKey:@"frameInWindow"];
|
||||
self.title = [aDecoder decodeObjectForKey:@"title"];
|
||||
self.subtitle = [aDecoder decodeObjectForKey:@"subtitle"];
|
||||
self.danceuiSource = [aDecoder decodeObjectForKey:@"danceuiSource"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
77
Pods/LookinServer/Src/Main/Shared/LookinDashboardBlueprint.h
generated
Normal file
77
Pods/LookinServer/Src/Main/Shared/LookinDashboardBlueprint.h
generated
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDashboardBlueprint.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/6/5.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LookinAttrIdentifiers.h"
|
||||
#import "LookinAttrType.h"
|
||||
|
||||
/**
|
||||
该对象定义了:
|
||||
- 每一个 Attr 的信息
|
||||
- 哪些 GroupID, SectionID, AttrID 是合法的
|
||||
- 这些 ID 的父子顺序,比如 LookinAttrGroup_Frame 包含哪些 Section
|
||||
- 这些 ID 展示顺序(比如哪个 Group 在前、哪个 Group 在后)
|
||||
*/
|
||||
@interface LookinDashboardBlueprint : NSObject
|
||||
|
||||
+ (NSArray<LookinAttrGroupIdentifier> *)groupIDs;
|
||||
|
||||
+ (NSArray<LookinAttrSectionIdentifier> *)sectionIDsForGroupID:(LookinAttrGroupIdentifier)groupID;
|
||||
|
||||
+ (NSArray<LookinAttrIdentifier> *)attrIDsForSectionID:(LookinAttrSectionIdentifier)sectionID;
|
||||
|
||||
/// 返回包含目标 attr 的 groupID 和 sectionID
|
||||
+ (void)getHostGroupID:(inout LookinAttrGroupIdentifier *)groupID sectionID:(inout LookinAttrSectionIdentifier *)sectionID fromAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 返回某个 group 的标题
|
||||
+ (NSString *)groupTitleWithGroupID:(LookinAttrGroupIdentifier)groupID;
|
||||
|
||||
/// 返回某个 section 的标题,nil 则表示不显示标题
|
||||
+ (NSString *)sectionTitleWithSectionID:(LookinAttrSectionIdentifier)secID;
|
||||
|
||||
/// 当某个 LookinAttribute 确定是 NSObject 类型时,该方法返回它具体是什么对象,比如 UIColor 等
|
||||
+ (LookinAttrType)objectAttrTypeWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 返回某个 LookinAttribute 代表的属性是哪一个类拥有的,比如 LookinAttrSec_UILabel_TextColor 是 UILabel 才有的
|
||||
+ (NSString *)classNameWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 一个 attr 要么属于 UIView 要么属于 CALayer,如果它属于 UIView 那么该方法返回 YES
|
||||
+ (BOOL)isUIViewPropertyWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 如果某个 attribute 是 enum,则这里会返回相应的 enum 的名称(如 @"NSTextAlignment"),进而可通过这个名称查询可用的枚举值列表
|
||||
+ (NSString *)enumListNameWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 如果返回 YES,则说明用户在 Lookin 里修改了该 Attribute 的值后,应该重新拉取和更新相关图层的位置、截图等信息
|
||||
+ (BOOL)needPatchAfterModificationWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 完整的名字
|
||||
+ (NSString *)fullTitleWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 在某些 textField 和 checkbox 里会显示这里返回的 title
|
||||
+ (NSString *)briefTitleWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 获取 getter 方法
|
||||
+ (SEL)getterWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 获取 setter 方法
|
||||
+ (SEL)setterWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 获取 “hideIfNil” 的值。如果为 YES,则当读取 getter 获取的 value 为 nil 时,Lookin 不会传输该 attr
|
||||
/// 如果为 NO,则即使 value 为 nil 也会传输(比如 label 的 text 属性,即使它是 nil 我们也要显示,所以它的 hideIfNil 应该为 NO)
|
||||
+ (BOOL)hideIfNilWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
/// 该属性需要的最低的 iOS 版本,比如 safeAreaInsets 从 iOS 11.0 开始出现,则该方法返回 11,如果返回 0 则表示不限制 iOS 版本(注意 Lookin 项目仅支持 iOS 8.0+)
|
||||
+ (NSInteger)minAvailableOSVersionWithAttrID:(LookinAttrIdentifier)attrID;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
1196
Pods/LookinServer/Src/Main/Shared/LookinDashboardBlueprint.m
generated
Normal file
1196
Pods/LookinServer/Src/Main/Shared/LookinDashboardBlueprint.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
172
Pods/LookinServer/Src/Main/Shared/LookinDefines.h
generated
Normal file
172
Pods/LookinServer/Src/Main/Shared/LookinDefines.h
generated
Normal file
@@ -0,0 +1,172 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinMessageProtocol.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2018/8/6.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#import <Appkit/Appkit.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma mark - Version
|
||||
|
||||
/// current connection protocol version of LookinServer
|
||||
static const int LOOKIN_SERVER_VERSION = 7;
|
||||
|
||||
/// current release version of LookinServer
|
||||
static NSString * const LOOKIN_SERVER_READABLE_VERSION = @"1.2.8";
|
||||
|
||||
/// current connection protocol version of LookinClient
|
||||
static const int LOOKIN_CLIENT_VERSION = 7;
|
||||
|
||||
/// the minimum connection protocol version supported by current LookinClient
|
||||
static const int LOOKIN_SUPPORTED_SERVER_MIN = 7;
|
||||
/// the maximum connection protocol version supported by current LookinClient
|
||||
static const int LOOKIN_SUPPORTED_SERVER_MAX = 7;
|
||||
|
||||
#pragma mark - Connection
|
||||
|
||||
/// LookinServer 在真机上会依次尝试监听 47175 ~ 47179 这几个端口
|
||||
static const int LookinUSBDeviceIPv4PortNumberStart = 47175;
|
||||
static const int LookinUSBDeviceIPv4PortNumberEnd = 47179;
|
||||
|
||||
/// LookinServer 在模拟器中会依次尝试监听 47164 ~ 47169 这几个端口
|
||||
static const int LookinSimulatorIPv4PortNumberStart = 47164;
|
||||
static const int LookinSimulatorIPv4PortNumberEnd = 47169;
|
||||
|
||||
enum {
|
||||
/// 确认两端是否可以响应通讯
|
||||
LookinRequestTypePing = 200,
|
||||
/// 请求 App 的截图、设备型号等信息
|
||||
LookinRequestTypeApp = 201,
|
||||
/// 请求 Hierarchy 信息
|
||||
LookinRequestTypeHierarchy = 202,
|
||||
/// 请求 screenshots 和 attrGroups 信息
|
||||
LookinRequestTypeHierarchyDetails = 203,
|
||||
/// 请求修改某个内置的 Attribute 的值
|
||||
LookinRequestTypeInbuiltAttrModification = 204,
|
||||
/// 修改某个 attr 后,请求一系列最新的 Screenshots、属性值等信息
|
||||
LookinRequestTypeAttrModificationPatch = 205,
|
||||
/// 执行某个方法
|
||||
LookinRequestTypeInvokeMethod = 206,
|
||||
/**
|
||||
@request: @{@"oid":}
|
||||
@response: LookinObject *
|
||||
*/
|
||||
LookinRequestTypeFetchObject = 207,
|
||||
|
||||
LookinRequestTypeFetchImageViewImage = 208,
|
||||
|
||||
LookinRequestTypeModifyRecognizerEnable = 209,
|
||||
|
||||
/// 请求 attribute group list
|
||||
LookinRequestTypeAllAttrGroups = 210,
|
||||
|
||||
/// 请求 iOS App 里某个 class 的所有 selector 名字列表(包括 superclass)
|
||||
LookinRequestTypeAllSelectorNames = 213,
|
||||
|
||||
/// 请求修改某个自定义 Attribute 的值
|
||||
LookinRequestTypeCustomAttrModification = 214,
|
||||
|
||||
/// 从 LookinServer 1.2.7 & Lookin 1.0.7 开始,该属性被废弃、不再使用
|
||||
LookinPush_BringForwardScreenshotTask = 303,
|
||||
|
||||
// 用户在 Lookin 客户端取消了之前 HierarchyDetails 的拉取
|
||||
LookinPush_CanceHierarchyDetails = 304,
|
||||
};
|
||||
|
||||
static NSString * const LookinParam_ViewLayerTag = @"tag";
|
||||
|
||||
static NSString * const LookinParam_SelectorName = @"sn";
|
||||
static NSString * const LookinParam_MethodType = @"mt";
|
||||
static NSString * const LookinParam_SelectorClassName = @"scn";
|
||||
|
||||
static NSString * const LookinStringFlag_VoidReturn = @"LOOKIN_TAG_RETURN_VALUE_VOID";
|
||||
|
||||
#pragma mark - Error
|
||||
|
||||
static NSString * const LookinErrorDomain = @"LookinError";
|
||||
|
||||
enum {
|
||||
LookinErrCode_Default = -400,
|
||||
/// Lookin 内部业务逻辑错误
|
||||
LookinErrCode_Inner = -401,
|
||||
/// PeerTalk 内部错误
|
||||
LookinErrCode_PeerTalk = -402,
|
||||
/// 连接不存在或已断开
|
||||
LookinErrCode_NoConnect = -403,
|
||||
/// ping 失败了,原因是 ping 请求超时
|
||||
LookinErrCode_PingFailForTimeout = -404,
|
||||
/// 请求超时未返回
|
||||
LookinErrCode_Timeout = -405,
|
||||
/// 有相同 Type 的新请求被发出,因此旧请求被丢弃
|
||||
LookinErrCode_Discard = -406,
|
||||
/// ping 失败了,原因是 app 主动报告自身正处于后台模式
|
||||
LookinErrCode_PingFailForBackgroundState = -407,
|
||||
|
||||
/// 没有找到对应的对象,可能已被释放
|
||||
LookinErrCode_ObjectNotFound = -500,
|
||||
/// 不支持修改当前类型的 LookinCodingValueType
|
||||
LookinErrCode_ModifyValueTypeInvalid = -501,
|
||||
LookinErrCode_Exception = -502,
|
||||
|
||||
// LookinServer 版本过高,要升级 client
|
||||
LookinErrCode_ServerVersionTooHigh = -600,
|
||||
// LookinServer 版本过低,要升级 server
|
||||
LookinErrCode_ServerVersionTooLow = -601,
|
||||
|
||||
// 不支持的文件类型
|
||||
LookinErrCode_UnsupportedFileType = -700,
|
||||
};
|
||||
|
||||
#define LookinErr_ObjNotFound [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_ObjectNotFound userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"Failed to get target object in iOS app", nil), NSLocalizedRecoverySuggestionErrorKey:NSLocalizedString(@"Perhaps the related object was deallocated. You can reload Lookin to get newest data.", nil)}]
|
||||
|
||||
#define LookinErr_NoConnect [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_NoConnect userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"The operation failed due to disconnection with the iOS app.", nil)}]
|
||||
|
||||
#define LookinErr_Inner [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"The operation failed due to an inner error.", nil)}]
|
||||
|
||||
#define LookinErrorMake(errorTitle, errorDetail) [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Default userInfo:@{NSLocalizedDescriptionKey:errorTitle, NSLocalizedRecoverySuggestionErrorKey:errorDetail}]
|
||||
|
||||
#define LookinErrorText_Timeout NSLocalizedString(@"Perhaps your iOS app is paused with breakpoint in Xcode, blocked by other tasks in main thread, or moved to background state.", nil)
|
||||
|
||||
#pragma mark - Colors
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define LookinColor UIColor
|
||||
#define LookinInsets UIEdgeInsets
|
||||
#define LookinImage UIImage
|
||||
#elif TARGET_OS_MAC
|
||||
#define LookinColor NSColor
|
||||
#define LookinInsets NSEdgeInsets
|
||||
#define LookinImage NSImage
|
||||
#endif
|
||||
|
||||
#define LookinColorRGBAMake(r, g, b, a) [LookinColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
|
||||
#define LookinColorMake(r, g, b) [LookinColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
|
||||
|
||||
#pragma mark - Preview
|
||||
|
||||
/// SCNNode 所允许的图片的最大的长和宽,单位是 px,这个值是 Scenekit 自身指定的
|
||||
/// Max pixel size of a SCNNode object. It is designated by SceneKit.
|
||||
static const double LookinNodeImageMaxLengthInPx = 16384;
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, LookinPreviewBitMask) {
|
||||
LookinPreviewBitMask_None = 0,
|
||||
|
||||
LookinPreviewBitMask_Selectable = 1 << 1,
|
||||
LookinPreviewBitMask_Unselectable = 1 << 2,
|
||||
|
||||
LookinPreviewBitMask_HasLight = 1 << 3,
|
||||
LookinPreviewBitMask_NoLight = 1 << 4
|
||||
};
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
186
Pods/LookinServer/Src/Main/Shared/LookinDisplayItem.h
generated
Normal file
186
Pods/LookinServer/Src/Main/Shared/LookinDisplayItem.h
generated
Normal file
@@ -0,0 +1,186 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayItem.h
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/15.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
#import "LookinObject.h"
|
||||
#import "LookinDefines.h"
|
||||
#import "LookinCustomDisplayItemInfo.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#import <Appkit/Appkit.h>
|
||||
#endif
|
||||
|
||||
@class LookinAttributesGroup, LookinIvarTrace, LookinPreviewItemLayer, LookinEventHandler, LKDisplayItemNode, LookinDisplayItem;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, LookinDisplayItemImageEncodeType) {
|
||||
LookinDisplayItemImageEncodeTypeNone, // 不进行 encode
|
||||
LookinDisplayItemImageEncodeTypeNSData, // 转换为 NSData
|
||||
LookinDisplayItemImageEncodeTypeImage // 使用 NSImage / UIImage 自身的 encode 方法
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, LookinDoNotFetchScreenshotReason) {
|
||||
// can sync screenshot
|
||||
LookinFetchScreenshotPermitted,
|
||||
// layer is too large
|
||||
LookinDoNotFetchScreenshotForTooLarge,
|
||||
// refused by user config in LookinServer
|
||||
LookinDoNotFetchScreenshotForUserConfig
|
||||
};
|
||||
|
||||
|
||||
typedef NS_ENUM(NSUInteger, LookinDisplayItemProperty) {
|
||||
// 当初次设置 delegate 对象时,会立即以该值触发一次 displayItem:propertyDidChange:
|
||||
LookinDisplayItemProperty_None,
|
||||
LookinDisplayItemProperty_FrameToRoot,
|
||||
LookinDisplayItemProperty_DisplayingInHierarchy,
|
||||
LookinDisplayItemProperty_InHiddenHierarchy,
|
||||
LookinDisplayItemProperty_IsExpandable,
|
||||
LookinDisplayItemProperty_IsExpanded,
|
||||
LookinDisplayItemProperty_SoloScreenshot,
|
||||
LookinDisplayItemProperty_GroupScreenshot,
|
||||
LookinDisplayItemProperty_IsSelected,
|
||||
LookinDisplayItemProperty_IsHovered,
|
||||
LookinDisplayItemProperty_AvoidSyncScreenshot,
|
||||
LookinDisplayItemProperty_InNoPreviewHierarchy,
|
||||
LookinDisplayItemProperty_IsInSearch,
|
||||
LookinDisplayItemProperty_HighlightedSearchString,
|
||||
};
|
||||
|
||||
@protocol LookinDisplayItemDelegate <NSObject>
|
||||
|
||||
- (void)displayItem:(LookinDisplayItem *)displayItem propertyDidChange:(LookinDisplayItemProperty)property;
|
||||
|
||||
@end
|
||||
|
||||
@interface LookinDisplayItem : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
/// 当 customInfo 不为 nil 时,意思是该 DisplayItem 为 UserCustom 配置的。此时,Encode 属性中仅 subitems 和 customAttrGroupList 属性有意义,其它几乎所有属性都无意义
|
||||
@property(nonatomic, strong) LookinCustomDisplayItemInfo *customInfo;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinDisplayItem *> *subitems;
|
||||
|
||||
@property(nonatomic, assign) BOOL isHidden;
|
||||
|
||||
@property(nonatomic, assign) float alpha;
|
||||
|
||||
@property(nonatomic, assign) CGRect frame;
|
||||
|
||||
@property(nonatomic, assign) CGRect bounds;
|
||||
|
||||
/// 不存在 subitems 时,该属性的值为 nil
|
||||
@property(nonatomic, strong) LookinImage *soloScreenshot;
|
||||
/// 无论是否存在 subitems,该属性始终存在
|
||||
@property(nonatomic, strong) LookinImage *groupScreenshot;
|
||||
|
||||
@property(nonatomic, strong) LookinObject *viewObject;
|
||||
@property(nonatomic, strong) LookinObject *layerObject;
|
||||
@property(nonatomic, strong) LookinObject *hostViewControllerObject;
|
||||
|
||||
/// attrGroups 列表
|
||||
@property(nonatomic, copy) NSArray<LookinAttributesGroup *> *attributesGroupList;
|
||||
/// 通过 lookin_customDebugInfos 返回的属性列表
|
||||
@property(nonatomic, copy) NSArray<LookinAttributesGroup *> *customAttrGroupList;
|
||||
/// attributesGroupList + customAttrGroupList
|
||||
- (NSArray<LookinAttributesGroup *> *)queryAllAttrGroupList;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinEventHandler *> *eventHandlers;
|
||||
|
||||
// 如果当前 item 代表 UIWindow 且是 keyWindow,则该属性为 YES
|
||||
@property(nonatomic, assign) BOOL representedAsKeyWindow;
|
||||
|
||||
|
||||
/// view 或 layer 的 backgroundColor,利用该属性来提前渲染 node 的背景色,使得用户感觉加载的快一点
|
||||
/// 注意有一个缺点是,理论上应该像 screenshot 一样拆成 soloBackgroundColor 和 groupBackgroundColor,这里的 backgroundColor 实际上是 soloBackgroundColor,因此某些场景的显示会有瑕疵
|
||||
@property(nonatomic, strong) LookinColor *backgroundColor;
|
||||
|
||||
/// 用户可以在 iOS 项目中添加 Lookin 自定义配置来显式地拒绝传输某些图层的图像,通常是屏蔽一些不重要的 View 以提升刷新速度。如果用户这么配置了,那么这个 shouldCaptureImage 就会被置为 NO
|
||||
/// 默认为 YES
|
||||
@property(nonatomic, assign) BOOL shouldCaptureImage;
|
||||
|
||||
/// 用户通过重写 lookin_customDebugInfos 而自定义的该实例的名字
|
||||
/// 可能为 nil
|
||||
@property(nonatomic, copy) NSString *customDisplayTitle;
|
||||
|
||||
/// 为 DanceUI SDK 预留的内部字段,用于文件跳转
|
||||
/// 可能为 nil
|
||||
@property(nonatomic, copy) NSString *danceuiSource;
|
||||
|
||||
#pragma mark - No Encode/Decode
|
||||
|
||||
@property(nonatomic, weak) id<LookinDisplayItemDelegate> previewItemDelegate;
|
||||
@property(nonatomic, weak) id<LookinDisplayItemDelegate> rowViewDelegate;
|
||||
|
||||
/// 父节点
|
||||
@property(nonatomic, weak) LookinDisplayItem *superItem;
|
||||
|
||||
/// 如果存在 viewObject 则返回 viewObject,否则返回 layerObject
|
||||
- (LookinObject *)displayingObject;
|
||||
|
||||
/// 在 hierarchy 中的层级,比如顶层的 UIWindow.indentLevel 为 0,UIWindow 的 subitem 的 indentLevel 为 1
|
||||
- (NSInteger)indentLevel;
|
||||
|
||||
/**
|
||||
该项是否被展开
|
||||
@note 假如自己没有被折叠,但是 superItem 被折叠了,则自己仍然不会被看到,但是 self.isExpanded 值仍然为 NO
|
||||
@note 如果 item 没有 subitems(也就是 isExpandable 为 NO),则该值没有意义。换句话说,在获取该值之前,必须先判断一下 isExpandable
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL isExpanded;
|
||||
|
||||
/// 如果有 subitems,则该属性返回 YES,否则返回 NO
|
||||
@property(nonatomic, assign, readonly) BOOL isExpandable;
|
||||
|
||||
/**
|
||||
是否能在 hierarchy panel 上被看到,假如有任意一层的父级元素的 isExpanded 为 NO,则 displayingInHierarchy 为 NO。如果所有父级元素的 isExpanded 均为 YES,则 displayingInHierarchy 为 YES
|
||||
*/
|
||||
@property(nonatomic, assign, readonly) BOOL displayingInHierarchy;
|
||||
|
||||
/**
|
||||
如果自身或任意一个上层元素的 isHidden 为 YES 或 alpha 为 0,则该属性返回 YES
|
||||
*/
|
||||
@property(nonatomic, assign, readonly) BOOL inHiddenHierarchy;
|
||||
|
||||
@property(nonatomic, assign) LookinDisplayItemImageEncodeType screenshotEncodeType;
|
||||
|
||||
/// Whether to fetch screenshot and why. Default to LookinFetchScreenshotPermitted.
|
||||
@property(nonatomic, assign) LookinDoNotFetchScreenshotReason doNotFetchScreenshotReason;
|
||||
|
||||
@property(nonatomic, weak) LookinPreviewItemLayer *previewLayer;
|
||||
|
||||
@property(nonatomic, weak) LKDisplayItemNode *previewNode;
|
||||
|
||||
/// 如果该值为 YES,则该 item 及所有子 item 均不会在 preview 中被显示出来,只能在 hierarchy 中选择。默认为 NO
|
||||
@property(nonatomic, assign) BOOL noPreview;
|
||||
|
||||
/// 如果自身或某个上级元素的 noPreview 值为 YES,则该方法返回 YES
|
||||
/// 注意:当 userCustom 为 YES 时,该属性也可能返回 YES
|
||||
@property(nonatomic, assign, readonly) BOOL inNoPreviewHierarchy;
|
||||
|
||||
/// 当小于 0 时表示未被设置
|
||||
@property(nonatomic, assign) NSInteger previewZIndex;
|
||||
|
||||
@property(nonatomic, assign) BOOL preferToBeCollapsed;
|
||||
|
||||
- (void)notifySelectionChangeToDelegates;
|
||||
- (void)notifyHoverChangeToDelegates;
|
||||
|
||||
/// 根据 subItems 属性将 items 打平为一维数组
|
||||
+ (NSArray<LookinDisplayItem *> *)flatItemsFromHierarchicalItems:(NSArray<LookinDisplayItem *> *)items;
|
||||
|
||||
@property(nonatomic, assign) BOOL hasDeterminedExpansion;
|
||||
|
||||
/// 设置当前是否处于搜索状态
|
||||
@property(nonatomic, assign) BOOL isInSearch;
|
||||
/// 因为搜索而应该被高亮的字符串
|
||||
@property(nonatomic, copy) NSString *highlightedSearchString;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
450
Pods/LookinServer/Src/Main/Shared/LookinDisplayItem.m
generated
Normal file
450
Pods/LookinServer/Src/Main/Shared/LookinDisplayItem.m
generated
Normal file
@@ -0,0 +1,450 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayItem.m
|
||||
// qmuidemo
|
||||
//
|
||||
// Created by Li Kai on 2018/11/15.
|
||||
// Copyright © 2018 QMUI Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LookinDisplayItem.h"
|
||||
#import "LookinAttributesGroup.h"
|
||||
#import "LookinAttributesSection.h"
|
||||
#import "LookinAttribute.h"
|
||||
#import "LookinEventHandler.h"
|
||||
#import "LookinIvarTrace.h"
|
||||
#import "Color+Lookin.h"
|
||||
#import "NSArray+Lookin.h"
|
||||
#import "NSObject+Lookin.h"
|
||||
#import "LookinDashboardBlueprint.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "UIColor+LookinServer.h"
|
||||
#import "UIImage+LookinServer.h"
|
||||
#elif TARGET_OS_MAC
|
||||
#endif
|
||||
|
||||
@interface LookinDisplayItem ()
|
||||
|
||||
@property(nonatomic, assign, readwrite) CGRect frameToRoot;
|
||||
@property(nonatomic, assign, readwrite) BOOL inNoPreviewHierarchy;
|
||||
@property(nonatomic, assign) NSInteger indentLevel;
|
||||
@property(nonatomic, assign, readwrite) BOOL isExpandable;
|
||||
@property(nonatomic, assign, readwrite) BOOL inHiddenHierarchy;
|
||||
@property(nonatomic, assign, readwrite) BOOL displayingInHierarchy;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LookinDisplayItem
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinDisplayItem *newDisplayItem = [[LookinDisplayItem allocWithZone:zone] init];
|
||||
newDisplayItem.subitems = [self.subitems lookin_map:^id(NSUInteger idx, LookinDisplayItem *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
newDisplayItem.customInfo = self.customInfo.copy;
|
||||
newDisplayItem.isHidden = self.isHidden;
|
||||
newDisplayItem.alpha = self.alpha;
|
||||
newDisplayItem.frame = self.frame;
|
||||
newDisplayItem.bounds = self.bounds;
|
||||
newDisplayItem.soloScreenshot = self.soloScreenshot;
|
||||
newDisplayItem.groupScreenshot = self.groupScreenshot;
|
||||
newDisplayItem.viewObject = self.viewObject.copy;
|
||||
newDisplayItem.layerObject = self.layerObject.copy;
|
||||
newDisplayItem.hostViewControllerObject = self.hostViewControllerObject.copy;
|
||||
newDisplayItem.attributesGroupList = [self.attributesGroupList lookin_map:^id(NSUInteger idx, LookinAttributesGroup *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
newDisplayItem.customAttrGroupList = [self.customAttrGroupList lookin_map:^id(NSUInteger idx, LookinAttributesGroup *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
newDisplayItem.eventHandlers = [self.eventHandlers lookin_map:^id(NSUInteger idx, LookinEventHandler *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
newDisplayItem.shouldCaptureImage = self.shouldCaptureImage;
|
||||
newDisplayItem.representedAsKeyWindow = self.representedAsKeyWindow;
|
||||
newDisplayItem.customDisplayTitle = self.customDisplayTitle;
|
||||
newDisplayItem.danceuiSource = self.danceuiSource;
|
||||
[newDisplayItem _updateDisplayingInHierarchyProperty];
|
||||
return newDisplayItem;
|
||||
}
|
||||
#pragma mark - <NSCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.customInfo forKey:@"customInfo"];
|
||||
[aCoder encodeObject:self.subitems forKey:@"subitems"];
|
||||
[aCoder encodeBool:self.isHidden forKey:@"hidden"];
|
||||
[aCoder encodeFloat:self.alpha forKey:@"alpha"];
|
||||
[aCoder encodeObject:self.viewObject forKey:@"viewObject"];
|
||||
[aCoder encodeObject:self.layerObject forKey:@"layerObject"];
|
||||
[aCoder encodeObject:self.hostViewControllerObject forKey:@"hostViewControllerObject"];
|
||||
[aCoder encodeObject:self.attributesGroupList forKey:@"attributesGroupList"];
|
||||
[aCoder encodeObject:self.customAttrGroupList forKey:@"customAttrGroupList"];
|
||||
[aCoder encodeBool:self.representedAsKeyWindow forKey:@"representedAsKeyWindow"];
|
||||
[aCoder encodeObject:self.eventHandlers forKey:@"eventHandlers"];
|
||||
[aCoder encodeBool:self.shouldCaptureImage forKey:@"shouldCaptureImage"];
|
||||
if (self.screenshotEncodeType == LookinDisplayItemImageEncodeTypeNSData) {
|
||||
[aCoder encodeObject:[self.soloScreenshot lookin_encodedObjectWithType:LookinCodingValueTypeImage] forKey:@"soloScreenshot"];
|
||||
[aCoder encodeObject:[self.groupScreenshot lookin_encodedObjectWithType:LookinCodingValueTypeImage] forKey:@"groupScreenshot"];
|
||||
} else if (self.screenshotEncodeType == LookinDisplayItemImageEncodeTypeImage) {
|
||||
[aCoder encodeObject:self.soloScreenshot forKey:@"soloScreenshot"];
|
||||
[aCoder encodeObject:self.groupScreenshot forKey:@"groupScreenshot"];
|
||||
}
|
||||
[aCoder encodeObject:self.customDisplayTitle forKey:@"customDisplayTitle"];
|
||||
[aCoder encodeObject:self.danceuiSource forKey:@"danceuiSource"];
|
||||
#if TARGET_OS_IPHONE
|
||||
[aCoder encodeCGRect:self.frame forKey:@"frame"];
|
||||
[aCoder encodeCGRect:self.bounds forKey:@"bounds"];
|
||||
[aCoder encodeObject:self.backgroundColor.lks_rgbaComponents forKey:@"backgroundColor"];
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
[aCoder encodeRect:self.frame forKey:@"frame"];
|
||||
[aCoder encodeRect:self.bounds forKey:@"bounds"];
|
||||
[aCoder encodeObject:self.backgroundColor.lookin_rgbaComponents forKey:@"backgroundColor"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.customInfo = [aDecoder decodeObjectForKey:@"customInfo"];
|
||||
self.subitems = [aDecoder decodeObjectForKey:@"subitems"];
|
||||
self.isHidden = [aDecoder decodeBoolForKey:@"hidden"];
|
||||
self.alpha = [aDecoder decodeFloatForKey:@"alpha"];
|
||||
self.viewObject = [aDecoder decodeObjectForKey:@"viewObject"];
|
||||
self.layerObject = [aDecoder decodeObjectForKey:@"layerObject"];
|
||||
self.hostViewControllerObject = [aDecoder decodeObjectForKey:@"hostViewControllerObject"];
|
||||
self.attributesGroupList = [aDecoder decodeObjectForKey:@"attributesGroupList"];
|
||||
self.customAttrGroupList = [aDecoder decodeObjectForKey:@"customAttrGroupList"];
|
||||
self.representedAsKeyWindow = [aDecoder decodeBoolForKey:@"representedAsKeyWindow"];
|
||||
|
||||
id soloScreenshotObj = [aDecoder decodeObjectForKey:@"soloScreenshot"];
|
||||
if (soloScreenshotObj) {
|
||||
if ([soloScreenshotObj isKindOfClass:[NSData class]]) {
|
||||
self.soloScreenshot = [soloScreenshotObj lookin_decodedObjectWithType:LookinCodingValueTypeImage];
|
||||
} else if ([soloScreenshotObj isKindOfClass:[LookinImage class]]) {
|
||||
self.soloScreenshot = soloScreenshotObj;
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
}
|
||||
|
||||
id groupScreenshotObj = [aDecoder decodeObjectForKey:@"groupScreenshot"];
|
||||
if (groupScreenshotObj) {
|
||||
if ([groupScreenshotObj isKindOfClass:[NSData class]]) {
|
||||
self.groupScreenshot = [groupScreenshotObj lookin_decodedObjectWithType:LookinCodingValueTypeImage];
|
||||
} else if ([groupScreenshotObj isKindOfClass:[LookinImage class]]) {
|
||||
self.groupScreenshot = groupScreenshotObj;
|
||||
} else {
|
||||
NSAssert(NO, @"");
|
||||
}
|
||||
}
|
||||
|
||||
self.eventHandlers = [aDecoder decodeObjectForKey:@"eventHandlers"];
|
||||
/// this property was added in LookinServer 1.1.3
|
||||
self.shouldCaptureImage = [aDecoder containsValueForKey:@"shouldCaptureImage"] ? [aDecoder decodeBoolForKey:@"shouldCaptureImage"] : YES;
|
||||
self.customDisplayTitle = [aDecoder decodeObjectForKey:@"customDisplayTitle"];
|
||||
self.danceuiSource = [aDecoder decodeObjectForKey:@"danceuiSource"];
|
||||
#if TARGET_OS_IPHONE
|
||||
self.frame = [aDecoder decodeCGRectForKey:@"frame"];
|
||||
self.bounds = [aDecoder decodeCGRectForKey:@"bounds"];
|
||||
self.backgroundColor = [UIColor lks_colorFromRGBAComponents:[aDecoder decodeObjectForKey:@"backgroundColor"]];
|
||||
#elif TARGET_OS_MAC
|
||||
self.frame = [aDecoder decodeRectForKey:@"frame"];
|
||||
self.bounds = [aDecoder decodeRectForKey:@"bounds"];
|
||||
self.backgroundColor = [NSColor lookin_colorFromRGBAComponents:[aDecoder decodeObjectForKey:@"backgroundColor"]];
|
||||
|
||||
#endif
|
||||
[self _updateDisplayingInHierarchyProperty];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
/// 在手机端,displayItem 被创建时会调用这个方法
|
||||
[self _updateDisplayingInHierarchyProperty];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (LookinObject *)displayingObject {
|
||||
return self.viewObject ? : self.layerObject;
|
||||
}
|
||||
|
||||
- (void)setAttributesGroupList:(NSArray<LookinAttributesGroup *> *)attributesGroupList {
|
||||
_attributesGroupList = attributesGroupList;
|
||||
|
||||
[_attributesGroupList enumerateObjectsUsingBlock:^(LookinAttributesGroup * _Nonnull group, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[group.attrSections enumerateObjectsUsingBlock:^(LookinAttributesSection * _Nonnull section, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[section.attributes enumerateObjectsUsingBlock:^(LookinAttribute * _Nonnull attr, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
attr.targetDisplayItem = self;
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setCustomAttrGroupList:(NSArray<LookinAttributesGroup *> *)customAttrGroupList {
|
||||
_customAttrGroupList = customAttrGroupList;
|
||||
// 传进来的时候就已经排好序了
|
||||
[customAttrGroupList enumerateObjectsUsingBlock:^(LookinAttributesGroup * _Nonnull group, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[group.attrSections enumerateObjectsUsingBlock:^(LookinAttributesSection * _Nonnull section, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[section.attributes enumerateObjectsUsingBlock:^(LookinAttribute * _Nonnull attr, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
attr.targetDisplayItem = self;
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setSubitems:(NSArray<LookinDisplayItem *> *)subitems {
|
||||
[_subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
obj.superItem = nil;
|
||||
}];
|
||||
|
||||
_subitems = subitems;
|
||||
|
||||
self.isExpandable = (subitems.count > 0);
|
||||
|
||||
[subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
NSAssert(!obj.superItem, @"");
|
||||
obj.superItem = self;
|
||||
|
||||
[obj _updateInHiddenHierarchyProperty];
|
||||
[obj _updateDisplayingInHierarchyProperty];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setIsExpandable:(BOOL)isExpandable {
|
||||
if (_isExpandable == isExpandable) {
|
||||
return;
|
||||
}
|
||||
_isExpandable = isExpandable;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_IsExpandable];
|
||||
}
|
||||
|
||||
- (void)setIsExpanded:(BOOL)isExpanded {
|
||||
if (_isExpanded == isExpanded) {
|
||||
return;
|
||||
}
|
||||
_isExpanded = isExpanded;
|
||||
[self.subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj _updateDisplayingInHierarchyProperty];
|
||||
}];
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_IsExpanded];
|
||||
}
|
||||
|
||||
- (void)setSoloScreenshot:(LookinImage *)soloScreenshot {
|
||||
if (_soloScreenshot == soloScreenshot) {
|
||||
return;
|
||||
}
|
||||
_soloScreenshot = soloScreenshot;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_SoloScreenshot];
|
||||
}
|
||||
|
||||
- (void)notifySelectionChangeToDelegates {
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_IsSelected];
|
||||
}
|
||||
|
||||
- (void)notifyHoverChangeToDelegates {
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_IsHovered];
|
||||
}
|
||||
|
||||
- (void)setDoNotFetchScreenshotReason:(LookinDoNotFetchScreenshotReason)doNotFetchScreenshotReason {
|
||||
if (_doNotFetchScreenshotReason == doNotFetchScreenshotReason) {
|
||||
return;
|
||||
}
|
||||
_doNotFetchScreenshotReason = doNotFetchScreenshotReason;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_AvoidSyncScreenshot];
|
||||
}
|
||||
|
||||
- (void)setGroupScreenshot:(LookinImage *)groupScreenshot {
|
||||
if (_groupScreenshot == groupScreenshot) {
|
||||
return;
|
||||
}
|
||||
_groupScreenshot = groupScreenshot;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_GroupScreenshot];
|
||||
}
|
||||
|
||||
- (void)setDisplayingInHierarchy:(BOOL)displayingInHierarchy {
|
||||
if (_displayingInHierarchy == displayingInHierarchy) {
|
||||
return;
|
||||
}
|
||||
_displayingInHierarchy = displayingInHierarchy;
|
||||
[self.subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj _updateDisplayingInHierarchyProperty];
|
||||
}];
|
||||
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_DisplayingInHierarchy];
|
||||
}
|
||||
|
||||
- (void)_updateDisplayingInHierarchyProperty {
|
||||
if (self.superItem && (!self.superItem.displayingInHierarchy || !self.superItem.isExpanded)) {
|
||||
self.displayingInHierarchy = NO;
|
||||
} else {
|
||||
self.displayingInHierarchy = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setIsHidden:(BOOL)isHidden {
|
||||
_isHidden = isHidden;
|
||||
[self _updateInHiddenHierarchyProperty];
|
||||
}
|
||||
|
||||
- (void)setAlpha:(float)alpha {
|
||||
_alpha = alpha;
|
||||
[self _updateInHiddenHierarchyProperty];
|
||||
}
|
||||
|
||||
- (void)setInHiddenHierarchy:(BOOL)inHiddenHierarchy {
|
||||
if (_inHiddenHierarchy == inHiddenHierarchy) {
|
||||
return;
|
||||
}
|
||||
_inHiddenHierarchy = inHiddenHierarchy;
|
||||
[self.subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj _updateInHiddenHierarchyProperty];
|
||||
}];
|
||||
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_InHiddenHierarchy];
|
||||
}
|
||||
|
||||
- (void)_updateInHiddenHierarchyProperty {
|
||||
if (self.superItem.inHiddenHierarchy || self.isHidden || self.alpha <= 0) {
|
||||
self.inHiddenHierarchy = YES;
|
||||
} else {
|
||||
self.inHiddenHierarchy = NO;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<LookinDisplayItem *> *)flatItemsFromHierarchicalItems:(NSArray<LookinDisplayItem *> *)items {
|
||||
NSMutableArray *resultArray = [NSMutableArray array];
|
||||
|
||||
[items enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (obj.superItem) {
|
||||
obj.indentLevel = obj.superItem.indentLevel + 1;
|
||||
}
|
||||
[resultArray addObject:obj];
|
||||
if (obj.subitems.count) {
|
||||
[resultArray addObjectsFromArray:[self flatItemsFromHierarchicalItems:obj.subitems]];
|
||||
}
|
||||
}];
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
if (self.viewObject) {
|
||||
return self.viewObject.rawClassName;
|
||||
} else if (self.layerObject) {
|
||||
return self.layerObject.rawClassName;
|
||||
} else {
|
||||
return [super description];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPreviewItemDelegate:(id<LookinDisplayItemDelegate>)previewItemDelegate {
|
||||
_previewItemDelegate = previewItemDelegate;
|
||||
|
||||
if (![previewItemDelegate respondsToSelector:@selector(displayItem:propertyDidChange:)]) {
|
||||
NSAssert(NO, @"");
|
||||
_previewItemDelegate = nil;
|
||||
return;
|
||||
}
|
||||
[self.previewItemDelegate displayItem:self propertyDidChange:LookinDisplayItemProperty_None];
|
||||
}
|
||||
|
||||
- (void)setRowViewDelegate:(id<LookinDisplayItemDelegate>)rowViewDelegate {
|
||||
if (_rowViewDelegate == rowViewDelegate) {
|
||||
return;
|
||||
}
|
||||
_rowViewDelegate = rowViewDelegate;
|
||||
|
||||
if (![rowViewDelegate respondsToSelector:@selector(displayItem:propertyDidChange:)]) {
|
||||
NSAssert(NO, @"");
|
||||
_rowViewDelegate = nil;
|
||||
return;
|
||||
}
|
||||
[self.rowViewDelegate displayItem:self propertyDidChange:LookinDisplayItemProperty_None];
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame {
|
||||
_frame = frame;
|
||||
[self recursivelyNotifyFrameToRootMayChange];
|
||||
}
|
||||
|
||||
- (void)recursivelyNotifyFrameToRootMayChange {
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_FrameToRoot];
|
||||
|
||||
[self.subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj recursivelyNotifyFrameToRootMayChange];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setBounds:(CGRect)bounds {
|
||||
_bounds = bounds;
|
||||
[self recursivelyNotifyFrameToRootMayChange];
|
||||
}
|
||||
|
||||
- (void)setInNoPreviewHierarchy:(BOOL)inNoPreviewHierarchy {
|
||||
if (_inNoPreviewHierarchy == inNoPreviewHierarchy) {
|
||||
return;
|
||||
}
|
||||
_inNoPreviewHierarchy = inNoPreviewHierarchy;
|
||||
[self.subitems enumerateObjectsUsingBlock:^(LookinDisplayItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj _updateInNoPreviewHierarchy];
|
||||
}];
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_InNoPreviewHierarchy];
|
||||
}
|
||||
|
||||
- (void)setNoPreview:(BOOL)noPreview {
|
||||
_noPreview = noPreview;
|
||||
[self _updateInNoPreviewHierarchy];
|
||||
}
|
||||
|
||||
- (void)_updateInNoPreviewHierarchy {
|
||||
if (self.superItem.inNoPreviewHierarchy || self.noPreview) {
|
||||
self.inNoPreviewHierarchy = YES;
|
||||
} else {
|
||||
self.inNoPreviewHierarchy = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_notifyDelegatesWith:(LookinDisplayItemProperty)property {
|
||||
[self.previewItemDelegate displayItem:self propertyDidChange:property];
|
||||
[self.rowViewDelegate displayItem:self propertyDidChange:property];
|
||||
}
|
||||
|
||||
- (void)setIsInSearch:(BOOL)isInSearch {
|
||||
_isInSearch = isInSearch;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_IsInSearch];
|
||||
}
|
||||
|
||||
- (void)setHighlightedSearchString:(NSString *)highlightedSearchString {
|
||||
_highlightedSearchString = highlightedSearchString;
|
||||
[self _notifyDelegatesWith:LookinDisplayItemProperty_HighlightedSearchString];
|
||||
}
|
||||
|
||||
- (NSArray<LookinAttributesGroup *> *)queryAllAttrGroupList {
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
if (self.attributesGroupList) {
|
||||
[array addObjectsFromArray:self.attributesGroupList];
|
||||
}
|
||||
if (self.customAttrGroupList) {
|
||||
[array addObjectsFromArray:self.customAttrGroupList];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
//- (void)dealloc
|
||||
//{
|
||||
// NSLog(@"moss dealloc -%@", self);
|
||||
//}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
51
Pods/LookinServer/Src/Main/Shared/LookinDisplayItemDetail.h
generated
Normal file
51
Pods/LookinServer/Src/Main/Shared/LookinDisplayItemDetail.h
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayItemDetail.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/2/19.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
@class LookinAttributesGroup;
|
||||
@class LookinDisplayItem;
|
||||
|
||||
@interface LookinDisplayItemDetail : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) unsigned long displayItemOid;
|
||||
|
||||
@property(nonatomic, strong) LookinImage *groupScreenshot;
|
||||
|
||||
@property(nonatomic, strong) LookinImage *soloScreenshot;
|
||||
|
||||
@property(nonatomic, strong) NSValue *frameValue;
|
||||
|
||||
@property(nonatomic, strong) NSValue *boundsValue;
|
||||
|
||||
@property(nonatomic, strong) NSNumber *hiddenValue;
|
||||
|
||||
@property(nonatomic, strong) NSNumber *alphaValue;
|
||||
|
||||
@property(nonatomic, copy) NSString *customDisplayTitle;
|
||||
|
||||
@property(nonatomic, copy) NSString *danceUISource;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinAttributesGroup *> *attributesGroupList;
|
||||
@property(nonatomic, copy) NSArray<LookinAttributesGroup *> *customAttrGroupList;
|
||||
|
||||
/// 注意 nil 和空数组的区别:nil 表示该属性无意义,空数组表示 subviews 为空
|
||||
/// Client 1.0.7 & Server 1.2.7 开始支持该属性
|
||||
/// 默认为 nil
|
||||
@property(nonatomic, copy) NSArray<LookinDisplayItem *> *subitems;
|
||||
|
||||
/// 当 Server 找不到 task 对应的图层时,会返回一个特殊的 LookinDisplayItemDetail 对象,这个对象会被设置 displayItemOid 和 failureCode,其中 failureCode 会被置为 -1
|
||||
/// Client 1.0.7 & Server 1.2.7 开始支持该属性
|
||||
/// 默认为 0
|
||||
@property(nonatomic, assign) NSInteger failureCode;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
71
Pods/LookinServer/Src/Main/Shared/LookinDisplayItemDetail.m
generated
Normal file
71
Pods/LookinServer/Src/Main/Shared/LookinDisplayItemDetail.m
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayItemDetail.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/2/19.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinDisplayItemDetail.h"
|
||||
#import "Image+Lookin.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "UIImage+LookinServer.h"
|
||||
#endif
|
||||
|
||||
@implementation LookinDisplayItemDetail
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:@(self.displayItemOid) forKey:@"displayItemOid"];
|
||||
[aCoder encodeObject:self.groupScreenshot.lookin_data forKey:@"groupScreenshot"];
|
||||
[aCoder encodeObject:self.soloScreenshot.lookin_data forKey:@"soloScreenshot"];
|
||||
[aCoder encodeObject:self.frameValue forKey:@"frameValue"];
|
||||
[aCoder encodeObject:self.boundsValue forKey:@"boundsValue"];
|
||||
[aCoder encodeObject:self.hiddenValue forKey:@"hiddenValue"];
|
||||
[aCoder encodeObject:self.alphaValue forKey:@"alphaValue"];
|
||||
[aCoder encodeObject:self.attributesGroupList forKey:@"attributesGroupList"];
|
||||
[aCoder encodeObject:self.customAttrGroupList forKey:@"customAttrGroupList"];
|
||||
[aCoder encodeObject:self.customDisplayTitle forKey:@"customDisplayTitle"];
|
||||
[aCoder encodeObject:self.danceUISource forKey:@"danceUISource"];
|
||||
[aCoder encodeInteger:self.failureCode forKey:@"failureCode"];
|
||||
if (self.subitems) {
|
||||
[aCoder encodeObject:self.subitems forKey:@"subitems"];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.displayItemOid = [[aDecoder decodeObjectForKey:@"displayItemOid"] unsignedLongValue];
|
||||
self.groupScreenshot = [[LookinImage alloc] initWithData:[aDecoder decodeObjectForKey:@"groupScreenshot"]];
|
||||
self.soloScreenshot = [[LookinImage alloc] initWithData:[aDecoder decodeObjectForKey:@"soloScreenshot"]];
|
||||
self.frameValue = [aDecoder decodeObjectForKey:@"frameValue"];
|
||||
self.boundsValue = [aDecoder decodeObjectForKey:@"boundsValue"];
|
||||
self.hiddenValue = [aDecoder decodeObjectForKey:@"hiddenValue"];
|
||||
self.alphaValue = [aDecoder decodeObjectForKey:@"alphaValue"];
|
||||
self.attributesGroupList = [aDecoder decodeObjectForKey:@"attributesGroupList"];
|
||||
self.customAttrGroupList = [aDecoder decodeObjectForKey:@"customAttrGroupList"];
|
||||
self.customDisplayTitle = [aDecoder decodeObjectForKey:@"customDisplayTitle"];
|
||||
self.danceUISource = [aDecoder decodeObjectForKey:@"danceUISource"];
|
||||
|
||||
if ([aDecoder containsValueForKey:@"failureCode"]) {
|
||||
self.failureCode = [aDecoder decodeIntegerForKey:@"failureCode"];
|
||||
} else {
|
||||
self.failureCode = 0;
|
||||
}
|
||||
|
||||
if ([aDecoder containsValueForKey:@"subitems"]) {
|
||||
self.subitems = [aDecoder decodeObjectForKey:@"subitems"];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
43
Pods/LookinServer/Src/Main/Shared/LookinEventHandler.h
generated
Normal file
43
Pods/LookinServer/Src/Main/Shared/LookinEventHandler.h
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinEventHandler.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/7.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class LookinObject, LookinIvarTrace, LookinStringTwoTuple;
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinEventHandlerType) {
|
||||
LookinEventHandlerTypeTargetAction,
|
||||
LookinEventHandlerTypeGesture
|
||||
};
|
||||
|
||||
@interface LookinEventHandler : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) LookinEventHandlerType handlerType;
|
||||
|
||||
/// 比如 "UIControlEventTouchUpInside", "UITapGestureRecognizer"
|
||||
@property(nonatomic, copy) NSString *eventName;
|
||||
/// tuple.first => @"<WRHomeView: 0xff>",tuple.second => @"handleTap"
|
||||
@property(nonatomic, copy) NSArray<LookinStringTwoTuple *> *targetActions;
|
||||
|
||||
/// 返回当前 recognizer 是继承自哪一个基本款 recognizer。
|
||||
/// 基本款 recognizer 指的是 TapRecognizer, PinchRecognizer 之类的常见 recognizer
|
||||
/// 如果当前 recognizer 本身就是基本款 recognizer,则该属性为 nil
|
||||
@property(nonatomic, copy) NSString *inheritedRecognizerName;
|
||||
@property(nonatomic, assign) BOOL gestureRecognizerIsEnabled;
|
||||
@property(nonatomic, copy) NSString *gestureRecognizerDelegator;
|
||||
@property(nonatomic, copy) NSArray<NSString *> *recognizerIvarTraces;
|
||||
/// recognizer 对象
|
||||
@property(nonatomic, assign) unsigned long long recognizerOid;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
71
Pods/LookinServer/Src/Main/Shared/LookinEventHandler.m
generated
Normal file
71
Pods/LookinServer/Src/Main/Shared/LookinEventHandler.m
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinEventHandler.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/7.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinEventHandler.h"
|
||||
#import "LookinObject.h"
|
||||
#import "LookinTuple.h"
|
||||
|
||||
#import "NSArray+Lookin.h"
|
||||
|
||||
@implementation LookinEventHandler
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinEventHandler *newHandler = [[LookinEventHandler allocWithZone:zone] init];
|
||||
newHandler.handlerType = self.handlerType;
|
||||
newHandler.eventName = self.eventName;
|
||||
newHandler.targetActions = [self.targetActions lookin_map:^id(NSUInteger idx, LookinStringTwoTuple *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
newHandler.gestureRecognizerIsEnabled = self.gestureRecognizerIsEnabled;
|
||||
newHandler.gestureRecognizerDelegator = self.gestureRecognizerDelegator;
|
||||
newHandler.inheritedRecognizerName = self.inheritedRecognizerName;
|
||||
newHandler.recognizerIvarTraces = self.recognizerIvarTraces.copy;
|
||||
newHandler.recognizerOid = self.recognizerOid;
|
||||
return newHandler;
|
||||
}
|
||||
|
||||
#pragma mark - <NSSecureCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:self.handlerType forKey:@"handlerType"];
|
||||
[aCoder encodeBool:self.gestureRecognizerIsEnabled forKey:@"gestureRecognizerIsEnabled"];
|
||||
[aCoder encodeObject:self.eventName forKey:@"eventName"];
|
||||
[aCoder encodeObject:self.gestureRecognizerDelegator forKey:@"gestureRecognizerDelegator"];
|
||||
[aCoder encodeObject:self.targetActions forKey:@"targetActions"];
|
||||
[aCoder encodeObject:self.inheritedRecognizerName forKey:@"inheritedRecognizerName"];
|
||||
[aCoder encodeObject:self.recognizerIvarTraces forKey:@"recognizerIvarTraces"];
|
||||
[aCoder encodeObject:@(self.recognizerOid) forKey:@"recognizerOid"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.handlerType = [aDecoder decodeIntegerForKey:@"handlerType"];
|
||||
self.gestureRecognizerIsEnabled = [aDecoder decodeBoolForKey:@"gestureRecognizerIsEnabled"];
|
||||
self.eventName = [aDecoder decodeObjectForKey:@"eventName"];
|
||||
self.gestureRecognizerDelegator = [aDecoder decodeObjectForKey:@"gestureRecognizerDelegator"];
|
||||
self.targetActions = [aDecoder decodeObjectForKey:@"targetActions"];
|
||||
self.inheritedRecognizerName = [aDecoder decodeObjectForKey:@"inheritedRecognizerName"];
|
||||
self.recognizerIvarTraces = [aDecoder decodeObjectForKey:@"recognizerIvarTraces"];
|
||||
self.recognizerOid = ((NSNumber *)[aDecoder decodeObjectForKey:@"recognizerOid"]).unsignedLongValue;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
32
Pods/LookinServer/Src/Main/Shared/LookinHierarchyFile.h
generated
Normal file
32
Pods/LookinServer/Src/Main/Shared/LookinHierarchyFile.h
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinHierarchyFile.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/5/12.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class LookinHierarchyInfo;
|
||||
|
||||
@interface LookinHierarchyFile : NSObject <NSSecureCoding>
|
||||
|
||||
/// 记录创建该文件的 LookinServer 的版本
|
||||
@property(nonatomic, assign) int serverVersion;
|
||||
|
||||
@property(nonatomic, strong) LookinHierarchyInfo *hierarchyInfo;
|
||||
|
||||
@property(nonatomic, copy) NSDictionary<NSNumber *, NSData *> *soloScreenshots;
|
||||
@property(nonatomic, copy) NSDictionary<NSNumber *, NSData *> *groupScreenshots;
|
||||
|
||||
/// 验证 file 的版本之类的是否和当前 Lookin 客户端匹配,如果没有问题则返回 nil,如果有问题则返回 error
|
||||
+ (NSError *)verifyHierarchyFile:(LookinHierarchyFile *)file;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
64
Pods/LookinServer/Src/Main/Shared/LookinHierarchyFile.m
generated
Normal file
64
Pods/LookinServer/Src/Main/Shared/LookinHierarchyFile.m
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinHierarchyFile.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/5/12.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinHierarchyFile.h"
|
||||
|
||||
#import "NSArray+Lookin.h"
|
||||
|
||||
@implementation LookinHierarchyFile
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInt:self.serverVersion forKey:@"serverVersion"];
|
||||
[aCoder encodeObject:self.hierarchyInfo forKey:@"hierarchyInfo"];
|
||||
[aCoder encodeObject:self.soloScreenshots forKey:@"soloScreenshots"];
|
||||
[aCoder encodeObject:self.groupScreenshots forKey:@"groupScreenshots"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.serverVersion = [aDecoder decodeIntForKey:@"serverVersion"];
|
||||
self.hierarchyInfo = [aDecoder decodeObjectForKey:@"hierarchyInfo"];
|
||||
self.soloScreenshots = [aDecoder decodeObjectForKey:@"soloScreenshots"];
|
||||
self.groupScreenshots = [aDecoder decodeObjectForKey:@"groupScreenshots"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSError *)verifyHierarchyFile:(LookinHierarchyFile *)hierarchyFile {
|
||||
if (![hierarchyFile isKindOfClass:[LookinHierarchyFile class]]) {
|
||||
return LookinErr_Inner;
|
||||
}
|
||||
|
||||
if (hierarchyFile.serverVersion < LOOKIN_SUPPORTED_SERVER_MIN) {
|
||||
// 文件版本太旧
|
||||
// 如果不存在 serverVersion 这个字段,说明版本是 6
|
||||
int fileVersion = hierarchyFile.serverVersion ? : 6;
|
||||
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)];
|
||||
return [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_ServerVersionTooLow userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"Failed to open the document.", nil), NSLocalizedRecoverySuggestionErrorKey:detail}];
|
||||
}
|
||||
|
||||
if (hierarchyFile.serverVersion > LOOKIN_SUPPORTED_SERVER_MAX) {
|
||||
// 文件版本太新
|
||||
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)];
|
||||
return [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_ServerVersionTooHigh userInfo:@{NSLocalizedDescriptionKey:NSLocalizedString(@"Failed to open the document.", nil), NSLocalizedRecoverySuggestionErrorKey:detail}];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
47
Pods/LookinServer/Src/Main/Shared/LookinHierarchyInfo.h
generated
Normal file
47
Pods/LookinServer/Src/Main/Shared/LookinHierarchyInfo.h
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayInfo.h
|
||||
// WeRead
|
||||
//
|
||||
// Created by Li Kai on 2018/10/22.
|
||||
// Copyright © 2018年 tencent. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinDefines.h"
|
||||
#import "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#import <Appkit/Appkit.h>
|
||||
#endif
|
||||
|
||||
@class LookinDisplayItem, LookinAttributesGroup, LookinAppInfo;
|
||||
|
||||
@interface LookinHierarchyInfo : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
/// version 可能为 nil,此时说明 Client 版本号 < 1.0.4
|
||||
+ (instancetype)staticInfoWithLookinVersion:(NSString *)version;
|
||||
|
||||
+ (instancetype)exportedInfo;
|
||||
|
||||
#endif
|
||||
|
||||
/// 这里其实就是顶端的那几个 UIWindow
|
||||
@property(nonatomic, copy) NSArray<LookinDisplayItem *> *displayItems;
|
||||
|
||||
@property(nonatomic, copy) NSDictionary<NSString *, id> *colorAlias;
|
||||
|
||||
@property(nonatomic, copy) NSArray<NSString *> *collapsedClassList;
|
||||
|
||||
@property(nonatomic, strong) LookinAppInfo *appInfo;
|
||||
|
||||
@property(nonatomic, assign) int serverVersion;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
106
Pods/LookinServer/Src/Main/Shared/LookinHierarchyInfo.m
generated
Normal file
106
Pods/LookinServer/Src/Main/Shared/LookinHierarchyInfo.m
generated
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinDisplayInfo.m
|
||||
// WeRead
|
||||
//
|
||||
// Created by Li Kai on 2018/10/22.
|
||||
// Copyright © 2018年 tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import "LookinHierarchyInfo.h"
|
||||
#import "LookinAttributesGroup.h"
|
||||
#import "LookinDisplayItem.h"
|
||||
#import "LookinAppInfo.h"
|
||||
#import "NSArray+Lookin.h"
|
||||
#import "NSString+Lookin.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "LKS_HierarchyDisplayItemsMaker.h"
|
||||
#import "LKSConfigManager.h"
|
||||
#import "LKS_CustomAttrSetterManager.h"
|
||||
#endif
|
||||
|
||||
@implementation LookinHierarchyInfo
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
+ (instancetype)staticInfoWithLookinVersion:(NSString *)version {
|
||||
BOOL readCustomInfo = NO;
|
||||
// Client 1.0.4 开始支持 customInfo
|
||||
if (version && [version lookin_numbericOSVersion] >= 10004) {
|
||||
readCustomInfo = YES;
|
||||
}
|
||||
|
||||
[[LKS_CustomAttrSetterManager sharedInstance] removeAll];
|
||||
|
||||
LookinHierarchyInfo *info = [LookinHierarchyInfo new];
|
||||
info.serverVersion = LOOKIN_SERVER_VERSION;
|
||||
info.displayItems = [LKS_HierarchyDisplayItemsMaker itemsWithScreenshots:NO attrList:NO lowImageQuality:NO readCustomInfo:readCustomInfo saveCustomSetter:YES];
|
||||
info.appInfo = [LookinAppInfo currentInfoWithScreenshot:NO icon:YES localIdentifiers:nil];
|
||||
info.collapsedClassList = [LKSConfigManager collapsedClassList];
|
||||
info.colorAlias = [LKSConfigManager colorAlias];
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)exportedInfo {
|
||||
LookinHierarchyInfo *info = [LookinHierarchyInfo new];
|
||||
info.serverVersion = LOOKIN_SERVER_VERSION;
|
||||
info.displayItems = [LKS_HierarchyDisplayItemsMaker itemsWithScreenshots:YES attrList:YES lowImageQuality:YES readCustomInfo:YES saveCustomSetter:NO];
|
||||
info.appInfo = [LookinAppInfo currentInfoWithScreenshot:NO icon:YES localIdentifiers:nil];
|
||||
info.collapsedClassList = [LKSConfigManager collapsedClassList];
|
||||
info.colorAlias = [LKSConfigManager colorAlias];
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark - <NSSecureCoding>
|
||||
|
||||
static NSString * const LookinHierarchyInfoCodingKey_DisplayItems = @"1";
|
||||
static NSString * const LookinHierarchyInfoCodingKey_AppInfo = @"2";
|
||||
static NSString * const LookinHierarchyInfoCodingKey_ColorAlias = @"3";
|
||||
static NSString * const LookinHierarchyInfoCodingKey_CollapsedClassList = @"4";
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.displayItems forKey:LookinHierarchyInfoCodingKey_DisplayItems];
|
||||
[aCoder encodeObject:self.colorAlias forKey:LookinHierarchyInfoCodingKey_ColorAlias];
|
||||
[aCoder encodeObject:self.collapsedClassList forKey:LookinHierarchyInfoCodingKey_CollapsedClassList];
|
||||
[aCoder encodeObject:self.appInfo forKey:LookinHierarchyInfoCodingKey_AppInfo];
|
||||
[aCoder encodeInt:self.serverVersion forKey:@"serverVersion"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.displayItems = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_DisplayItems];
|
||||
self.colorAlias = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_ColorAlias];
|
||||
self.collapsedClassList = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_CollapsedClassList];
|
||||
self.appInfo = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_AppInfo];
|
||||
self.serverVersion = [aDecoder decodeIntForKey:@"serverVersion"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinHierarchyInfo *newAppInfo = [[LookinHierarchyInfo allocWithZone:zone] init];
|
||||
newAppInfo.serverVersion = self.serverVersion;
|
||||
newAppInfo.appInfo = self.appInfo.copy;
|
||||
newAppInfo.collapsedClassList = self.collapsedClassList;
|
||||
newAppInfo.colorAlias = self.colorAlias;
|
||||
newAppInfo.displayItems = [self.displayItems lookin_map:^id(NSUInteger idx, LookinDisplayItem *oldItem) {
|
||||
return oldItem.copy;
|
||||
}];
|
||||
|
||||
return newAppInfo;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
42
Pods/LookinServer/Src/Main/Shared/LookinObject.h
generated
Normal file
42
Pods/LookinServer/Src/Main/Shared/LookinObject.h
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinObject.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/4/20.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class LookinObjectIvar, LookinIvarTrace;
|
||||
|
||||
@interface LookinObject : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
+ (instancetype)instanceWithObject:(NSObject *)object;
|
||||
#endif
|
||||
|
||||
@property(nonatomic, assign) unsigned long oid;
|
||||
|
||||
@property(nonatomic, copy) NSString *memoryAddress;
|
||||
|
||||
/**
|
||||
比如有一个 UILabel 对象,则它的 classChainList 为 @[@"UILabel", @"UIView", @"UIResponder", @"NSObject"],而它的 ivarList 长度为 4,idx 从小到大分别是 UILabel 层级的 ivars, UIView 层级的 ivars.....
|
||||
*/
|
||||
@property(nonatomic, copy) NSArray<NSString *> *classChainList;
|
||||
|
||||
@property(nonatomic, copy) NSString *specialTrace;
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinIvarTrace *> *ivarTraces;
|
||||
|
||||
/// 没有 demangle,会包含 Swift Module Name
|
||||
/// 在 Lookin 的展示中,绝大多数情况下应该使用 lk_demangledSwiftName
|
||||
- (NSString *)rawClassName;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
82
Pods/LookinServer/Src/Main/Shared/LookinObject.m
generated
Normal file
82
Pods/LookinServer/Src/Main/Shared/LookinObject.m
generated
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinObject.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/4/20.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
#import "LookinObject.h"
|
||||
#import "LookinIvarTrace.h"
|
||||
#import "NSArray+Lookin.h"
|
||||
#import "NSString+Lookin.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "NSObject+LookinServer.h"
|
||||
#endif
|
||||
|
||||
@implementation LookinObject
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
+ (instancetype)instanceWithObject:(NSObject *)object {
|
||||
LookinObject *lookinObj = [LookinObject new];
|
||||
lookinObj.oid = [object lks_registerOid];
|
||||
|
||||
lookinObj.memoryAddress = [NSString stringWithFormat:@"%p", object];
|
||||
lookinObj.classChainList = [object lks_classChainList];
|
||||
|
||||
lookinObj.specialTrace = object.lks_specialTrace;
|
||||
lookinObj.ivarTraces = object.lks_ivarTraces;
|
||||
|
||||
return lookinObj;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinObject *newObject = [[LookinObject allocWithZone:zone] init];
|
||||
newObject.oid = self.oid;
|
||||
newObject.memoryAddress = self.memoryAddress;
|
||||
newObject.classChainList = self.classChainList;
|
||||
newObject.specialTrace = self.specialTrace;
|
||||
newObject.ivarTraces = [self.ivarTraces lookin_map:^id(NSUInteger idx, LookinIvarTrace *value) {
|
||||
return value.copy;
|
||||
}];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
#pragma mark - <NSSecureCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:@(self.oid) forKey:@"oid"];
|
||||
[aCoder encodeObject:self.memoryAddress forKey:@"memoryAddress"];
|
||||
[aCoder encodeObject:self.classChainList forKey:@"classChainList"];
|
||||
[aCoder encodeObject:self.specialTrace forKey:@"specialTrace"];
|
||||
[aCoder encodeObject:self.ivarTraces forKey:@"ivarTraces"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.oid = [(NSNumber *)[aDecoder decodeObjectForKey:@"oid"] unsignedLongValue];
|
||||
self.memoryAddress = [aDecoder decodeObjectForKey:@"memoryAddress"];
|
||||
self.classChainList = [aDecoder decodeObjectForKey:@"classChainList"];
|
||||
self.specialTrace = [aDecoder decodeObjectForKey:@"specialTrace"];
|
||||
self.ivarTraces = [aDecoder decodeObjectForKey:@"ivarTraces"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)rawClassName {
|
||||
return self.classChainList.firstObject;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
67
Pods/LookinServer/Src/Main/Shared/LookinStaticAsyncUpdateTask.h
generated
Normal file
67
Pods/LookinServer/Src/Main/Shared/LookinStaticAsyncUpdateTask.h
generated
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinStaticAsyncUpdateTask.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/6/21.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinDefines.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinStaticAsyncUpdateTaskType) {
|
||||
LookinStaticAsyncUpdateTaskTypeNoScreenshot,
|
||||
LookinStaticAsyncUpdateTaskTypeSoloScreenshot,
|
||||
LookinStaticAsyncUpdateTaskTypeGroupScreenshot
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, LookinDetailUpdateTaskAttrRequest) {
|
||||
/// 由 Server 端自己决定:同一批 task 里,server 端会保证同一个 layer 只会构造一次 attr
|
||||
/// 在 Lookin turbo 模式下,由于同一个 layer 的 task 可能位于不同批的 task 里,因此这会导致冗余的 attr 构造行为、浪费一定时间
|
||||
LookinDetailUpdateTaskAttrRequest_Automatic,
|
||||
/// 需要返回 attr
|
||||
LookinDetailUpdateTaskAttrRequest_Need,
|
||||
/// 不需要返回 attr
|
||||
LookinDetailUpdateTaskAttrRequest_NotNeed
|
||||
};
|
||||
|
||||
/// 业务重写了 isEqual
|
||||
@interface LookinStaticAsyncUpdateTask : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, assign) unsigned long oid;
|
||||
|
||||
@property(nonatomic, assign) LookinStaticAsyncUpdateTaskType taskType;
|
||||
|
||||
/// 是否需要返回 attr 数据,默认为 Automatic
|
||||
/// Client 1.0.7 & Server 1.2.7 开始支持这个参数
|
||||
@property(nonatomic, assign) LookinDetailUpdateTaskAttrRequest attrRequest;
|
||||
|
||||
/// 如果置为 YES,则 server 侧会返回这些基础信息:frameValue, boundsValue, hiddenValue, alphaValue
|
||||
/// 默认为 NO
|
||||
/// Client 1.0.7 & Server 1.2.7 开始支持这个参数
|
||||
@property(nonatomic, assign) BOOL needBasisVisualInfo;
|
||||
|
||||
/// 如果置为 YES,则 server 侧会返回 subitems
|
||||
/// 默认为 NO
|
||||
/// Client 1.0.7 & Server 1.2.7 开始支持这个参数
|
||||
@property(nonatomic, assign) BOOL needSubitems;
|
||||
|
||||
/// Client 1.0.4 开始加入这个参数
|
||||
@property(nonatomic, copy) NSString *clientReadableVersion;
|
||||
|
||||
#pragma mark - Non Coding
|
||||
|
||||
@property(nonatomic, assign) CGSize frameSize;
|
||||
|
||||
@end
|
||||
|
||||
@interface LookinStaticAsyncUpdateTasksPackage : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, copy) NSArray<LookinStaticAsyncUpdateTask *> *tasks;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
105
Pods/LookinServer/Src/Main/Shared/LookinStaticAsyncUpdateTask.m
generated
Normal file
105
Pods/LookinServer/Src/Main/Shared/LookinStaticAsyncUpdateTask.m
generated
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinStaticAsyncUpdateTask.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/6/21.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinStaticAsyncUpdateTask.h"
|
||||
|
||||
@implementation LookinStaticAsyncUpdateTask
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:@(self.oid) forKey:@"oid"];
|
||||
[aCoder encodeInteger:self.taskType forKey:@"taskType"];
|
||||
[aCoder encodeObject:self.clientReadableVersion forKey:@"clientReadableVersion"];
|
||||
[aCoder encodeInteger:self.attrRequest forKey:@"attrRequest"];
|
||||
[aCoder encodeBool:self.needBasisVisualInfo forKey:@"needBasisVisualInfo"];
|
||||
[aCoder encodeBool:self.needSubitems forKey:@"needSubitems"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.oid = [[aDecoder decodeObjectForKey:@"oid"] unsignedLongValue];
|
||||
self.taskType = [aDecoder decodeIntegerForKey:@"taskType"];
|
||||
self.clientReadableVersion = [aDecoder decodeObjectForKey:@"clientReadableVersion"];
|
||||
if ([aDecoder containsValueForKey:@"attrRequest"]) {
|
||||
NSInteger value = [aDecoder decodeIntegerForKey:@"attrRequest"];
|
||||
if (value >= LookinDetailUpdateTaskAttrRequest_Automatic && value <= LookinDetailUpdateTaskAttrRequest_NotNeed) {
|
||||
self.attrRequest = value;
|
||||
} else {
|
||||
self.attrRequest = LookinDetailUpdateTaskAttrRequest_Automatic;
|
||||
}
|
||||
} else {
|
||||
self.attrRequest = LookinDetailUpdateTaskAttrRequest_Automatic;
|
||||
}
|
||||
|
||||
if ([aDecoder containsValueForKey:@"needBasisVisualInfo"]) {
|
||||
self.needBasisVisualInfo = [aDecoder decodeBoolForKey:@"needBasisVisualInfo"];
|
||||
} else {
|
||||
self.needBasisVisualInfo = NO;
|
||||
}
|
||||
|
||||
if ([aDecoder containsValueForKey:@"needSubitems"]) {
|
||||
self.needSubitems = [aDecoder decodeBoolForKey:@"needSubitems"];
|
||||
} else {
|
||||
self.needSubitems = NO;
|
||||
}
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return self.oid ^ self.taskType ^ self.attrRequest ^ self.needBasisVisualInfo ^ self.needSubitems;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[LookinStaticAsyncUpdateTask class]]) {
|
||||
return NO;
|
||||
}
|
||||
LookinStaticAsyncUpdateTask *targetTask = object;
|
||||
if (self.oid == targetTask.oid
|
||||
&& self.taskType == targetTask.taskType
|
||||
&& self.attrRequest == targetTask.attrRequest
|
||||
&& self.needBasisVisualInfo == targetTask.needBasisVisualInfo
|
||||
&& self.needSubitems == targetTask.needSubitems) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation LookinStaticAsyncUpdateTasksPackage
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.tasks forKey:@"tasks"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.tasks = [aDecoder decodeObjectForKey:@"tasks"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
31
Pods/LookinServer/Src/Main/Shared/LookinTuple.h
generated
Normal file
31
Pods/LookinServer/Src/Main/Shared/LookinTuple.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinTuples.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/14.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LookinTwoTuple : NSObject <NSSecureCoding>
|
||||
|
||||
@property(nonatomic, strong) NSObject *first;
|
||||
@property(nonatomic, strong) NSObject *second;
|
||||
|
||||
@end
|
||||
|
||||
@interface LookinStringTwoTuple : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
+ (instancetype)tupleWithFirst:(NSString *)firstString second:(NSString *)secondString;
|
||||
|
||||
@property(nonatomic, copy) NSString *first;
|
||||
@property(nonatomic, copy) NSString *second;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
93
Pods/LookinServer/Src/Main/Shared/LookinTuple.m
generated
Normal file
93
Pods/LookinServer/Src/Main/Shared/LookinTuple.m
generated
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinTuples.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/14.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinTuple.h"
|
||||
|
||||
@implementation LookinTwoTuple
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.first forKey:@"first"];
|
||||
[aCoder encodeObject:self.second forKey:@"second"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.first = [aDecoder decodeObjectForKey:@"first"];
|
||||
self.second = [aDecoder decodeObjectForKey:@"second"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return self.first.hash ^ self.second.hash;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[LookinTwoTuple class]]) {
|
||||
return NO;
|
||||
}
|
||||
LookinTwoTuple *comparedObj = object;
|
||||
if ([self.first isEqual:comparedObj.first] && [self.second isEqual:comparedObj.second]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation LookinStringTwoTuple
|
||||
|
||||
+ (instancetype)tupleWithFirst:(NSString *)firstString second:(NSString *)secondString {
|
||||
LookinStringTwoTuple *tuple = [LookinStringTwoTuple new];
|
||||
tuple.first = firstString;
|
||||
tuple.second = secondString;
|
||||
return tuple;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCopying>
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
LookinStringTwoTuple *newTuple = [[LookinStringTwoTuple allocWithZone:zone] init];
|
||||
newTuple.first = self.first;
|
||||
newTuple.second = self.second;
|
||||
return newTuple;
|
||||
}
|
||||
|
||||
#pragma mark - <NSCoding>
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.first forKey:@"first"];
|
||||
[aCoder encodeObject:self.second forKey:@"second"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.first = [aDecoder decodeObjectForKey:@"first"];
|
||||
self.second = [aDecoder decodeObjectForKey:@"second"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
23
Pods/LookinServer/Src/Main/Shared/LookinWeakContainer.h
generated
Normal file
23
Pods/LookinServer/Src/Main/Shared/LookinWeakContainer.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinWeakContainer.h
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/14.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LookinWeakContainer : NSObject
|
||||
|
||||
+ (instancetype)containerWithObject:(id)object;
|
||||
|
||||
@property (nonatomic, weak) id object;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
43
Pods/LookinServer/Src/Main/Shared/LookinWeakContainer.m
generated
Normal file
43
Pods/LookinServer/Src/Main/Shared/LookinWeakContainer.m
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// LookinWeakContainer.m
|
||||
// Lookin
|
||||
//
|
||||
// Created by Li Kai on 2019/8/14.
|
||||
// https://lookin.work
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import "LookinWeakContainer.h"
|
||||
|
||||
@implementation LookinWeakContainer
|
||||
|
||||
+ (instancetype)containerWithObject:(id)object {
|
||||
LookinWeakContainer *container = [LookinWeakContainer new];
|
||||
container.object = object;
|
||||
return container;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [self.object hash];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[LookinWeakContainer class]]) {
|
||||
return NO;
|
||||
}
|
||||
LookinWeakContainer *comparedObj = object;
|
||||
if ([self.object isEqual:comparedObj.object]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
136
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTChannel.h
generated
Normal file
136
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTChannel.h
generated
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Represents a communication channel between two endpoints talking the same
|
||||
// Lookin_PTProtocol.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dispatch/dispatch.h>
|
||||
#import <netinet/in.h>
|
||||
#import <sys/socket.h>
|
||||
|
||||
#import "Lookin_PTProtocol.h"
|
||||
#import "Lookin_PTUSBHub.h"
|
||||
|
||||
@class Lookin_PTData, Lookin_PTAddress;
|
||||
@protocol Lookin_PTChannelDelegate;
|
||||
|
||||
@interface Lookin_PTChannel : NSObject
|
||||
|
||||
// Delegate
|
||||
@property (strong) id<Lookin_PTChannelDelegate> delegate;
|
||||
|
||||
// Communication protocol. Must not be nil.
|
||||
@property Lookin_PTProtocol *protocol;
|
||||
|
||||
// YES if this channel is a listening server
|
||||
@property (readonly) BOOL isListening;
|
||||
|
||||
// YES if this channel is a connected peer
|
||||
@property (readonly) BOOL isConnected;
|
||||
|
||||
// Arbitrary attachment. Note that if you set this, the object will grow by
|
||||
// 8 bytes (64 bits).
|
||||
@property (strong) id userInfo;
|
||||
|
||||
@property(nonatomic, assign) int uniqueID;
|
||||
@property(nonatomic, assign) NSInteger targetPort;
|
||||
- (NSString *)debugTag;
|
||||
|
||||
// Create a new channel using the shared Lookin_PTProtocol for the current dispatch
|
||||
// queue, with *delegate*.
|
||||
+ (Lookin_PTChannel*)channelWithDelegate:(id<Lookin_PTChannelDelegate>)delegate;
|
||||
|
||||
|
||||
// Initialize a new frame channel, configuring it to use the calling queue's
|
||||
// protocol instance (as returned by [Lookin_PTProtocol sharedProtocolForQueue:
|
||||
// dispatch_get_current_queue()])
|
||||
- (id)init;
|
||||
|
||||
// Initialize a new frame channel with a specific protocol.
|
||||
- (id)initWithProtocol:(Lookin_PTProtocol*)protocol;
|
||||
|
||||
// Initialize a new frame channel with a specific protocol and delegate.
|
||||
- (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate;
|
||||
|
||||
|
||||
// Connect to a TCP port on a device connected over USB
|
||||
- (void)connectToPort:(int)port overUSBHub:(Lookin_PTUSBHub*)usbHub deviceID:(NSNumber*)deviceID callback:(void(^)(NSError *error))callback;
|
||||
|
||||
// Connect to a TCP port at IPv4 address. Provided port must NOT be in network
|
||||
// byte order. Provided in_addr_t must NOT be in network byte order. A value returned
|
||||
// from inet_aton() will be in network byte order. You can use a value of inet_aton()
|
||||
// as the address parameter here, but you must flip the byte order before passing the
|
||||
// in_addr_t to this function.
|
||||
- (void)connectToPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error, Lookin_PTAddress *address))callback;
|
||||
|
||||
// Listen for connections on port and address, effectively starting a socket
|
||||
// server. Provided port must NOT be in network byte order. Provided in_addr_t
|
||||
// must NOT be in network byte order.
|
||||
// For this to make sense, you should provide a onAccept block handler
|
||||
// or a delegate implementing ioFrameChannel:didAcceptConnection:.
|
||||
- (void)listenOnPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error))callback;
|
||||
|
||||
// Send a frame with an optional payload and optional callback.
|
||||
// If *callback* is not NULL, the block is invoked when either an error occured
|
||||
// or when the frame (and payload, if any) has been completely sent.
|
||||
- (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback;
|
||||
|
||||
// Lower-level method to assign a connected dispatch IO channel to this channel
|
||||
- (BOOL)startReadingFromConnectedChannel:(dispatch_io_t)channel error:(__autoreleasing NSError**)error;
|
||||
|
||||
// Close the channel, preventing further reading and writing. Any ongoing and
|
||||
// queued reads and writes will be aborted.
|
||||
- (void)close;
|
||||
|
||||
// "graceful" close -- any ongoing and queued reads and writes will complete
|
||||
// before the channel ends.
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Wraps a mapped dispatch_data_t object. The memory pointed to by *data* is
|
||||
// valid until *dispatchData* is deallocated (normally when the receiver is
|
||||
// deallocated).
|
||||
@interface Lookin_PTData : NSObject
|
||||
@property (readonly) dispatch_data_t dispatchData;
|
||||
@property (readonly) void *data;
|
||||
@property (readonly) size_t length;
|
||||
@end
|
||||
|
||||
|
||||
// Represents a peer's address
|
||||
@interface Lookin_PTAddress : NSObject
|
||||
// For network addresses, this is the IP address in textual format
|
||||
@property (readonly) NSString *name;
|
||||
// For network addresses, this is the port number. Otherwise 0 (zero).
|
||||
@property (readonly) NSInteger port;
|
||||
@end
|
||||
|
||||
|
||||
// Protocol for Lookin_PTChannel delegates
|
||||
@protocol Lookin_PTChannelDelegate <NSObject>
|
||||
|
||||
@required
|
||||
// Invoked when a new frame has arrived on a channel.
|
||||
- (void)ioFrameChannel:(Lookin_PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(Lookin_PTData*)payload;
|
||||
|
||||
@optional
|
||||
// Invoked to accept an incoming frame on a channel. Reply NO ignore the
|
||||
// incoming frame. If not implemented by the delegate, all frames are accepted.
|
||||
- (BOOL)ioFrameChannel:(Lookin_PTChannel*)channel shouldAcceptFrameOfType:(uint32_t)type tag:(uint32_t)tag payloadSize:(uint32_t)payloadSize;
|
||||
|
||||
// Invoked when the channel closed. If it closed because of an error, *error* is
|
||||
// a non-nil NSError object.
|
||||
- (void)ioFrameChannel:(Lookin_PTChannel*)channel didEndWithError:(NSError*)error;
|
||||
|
||||
// For listening channels, this method is invoked when a new connection has been
|
||||
// accepted.
|
||||
- (void)ioFrameChannel:(Lookin_PTChannel*)channel didAcceptConnection:(Lookin_PTChannel*)otherChannel fromAddress:(Lookin_PTAddress*)address;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
675
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTChannel.m
generated
Normal file
675
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTChannel.m
generated
Normal file
@@ -0,0 +1,675 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
#import "Lookin_PTChannel.h"
|
||||
#import "Lookin_PTPrivate.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/un.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
// Read member of sockaddr_in without knowing the family
|
||||
#define PT_SOCKADDR_ACCESS(ss, member4, member6) \
|
||||
(((ss)->ss_family == AF_INET) ? ( \
|
||||
((const struct sockaddr_in *)(ss))->member4 \
|
||||
) : ( \
|
||||
((const struct sockaddr_in6 *)(ss))->member6 \
|
||||
))
|
||||
|
||||
// Connection state (storage: uint8_t)
|
||||
#define kConnStateNone 0
|
||||
#define kConnStateConnecting 1
|
||||
#define kConnStateConnected 2
|
||||
#define kConnStateListening 3
|
||||
|
||||
// Delegate support optimization (storage: uint8_t)
|
||||
#define kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize 1
|
||||
#define kDelegateFlagImplements_ioFrameChannel_didEndWithError 2
|
||||
#define kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress 4
|
||||
|
||||
|
||||
static int ChannelInstanceCount = 0;
|
||||
static int ChannelUniqueID = 0;
|
||||
|
||||
#pragma mark -
|
||||
// Note: We are careful about the size of this struct as each connected peer
|
||||
// implies one allocation of this struct.
|
||||
@interface Lookin_PTChannel () {
|
||||
dispatch_io_t dispatchObj_channel_;
|
||||
dispatch_source_t dispatchObj_source_;
|
||||
NSError *endError_; // 64 bit
|
||||
@public // here be hacks
|
||||
id<Lookin_PTChannelDelegate> delegate_; // 64 bit
|
||||
uint8_t delegateFlags_; // 8 bit
|
||||
@private
|
||||
uint8_t connState_; // 8 bit
|
||||
//char padding_[6]; // 48 bit -- only if allocation speed is important
|
||||
}
|
||||
- (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate;
|
||||
- (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD;
|
||||
@end
|
||||
static const uint8_t kUserInfoKey;
|
||||
|
||||
#pragma mark -
|
||||
@interface Lookin_PTData ()
|
||||
- (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@interface Lookin_PTAddress () {
|
||||
struct sockaddr_storage sockaddr_;
|
||||
}
|
||||
- (id)initWithSockaddr:(const struct sockaddr_storage*)addr;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@implementation Lookin_PTChannel
|
||||
|
||||
@synthesize protocol = protocol_;
|
||||
|
||||
|
||||
+ (Lookin_PTChannel*)channelWithDelegate:(id<Lookin_PTChannelDelegate>)delegate {
|
||||
return [[Lookin_PTChannel alloc] initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()] delegate:delegate];
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate {
|
||||
if (!(self = [super init])) return nil;
|
||||
protocol_ = protocol;
|
||||
self.delegate = delegate;
|
||||
|
||||
[self didInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithProtocol:(Lookin_PTProtocol*)protocol {
|
||||
if (!(self = [super init])) return nil;
|
||||
protocol_ = protocol;
|
||||
|
||||
[self didInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (id)init {
|
||||
[self didInit];
|
||||
|
||||
return [self initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()]];
|
||||
}
|
||||
|
||||
- (void)didInit {
|
||||
ChannelUniqueID++;
|
||||
ChannelInstanceCount++;
|
||||
self.uniqueID = ChannelUniqueID;
|
||||
// NSLog(@"LookinServer - Init channel(ID: %@). Total count: %@", @(self.uniqueID), @(ChannelInstanceCount));
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
ChannelInstanceCount--;
|
||||
// NSLog(@"LookinServer - Dealloc channel%@. Still lives count: %@", self.debugTag, @(ChannelInstanceCount));
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchObj_channel_) dispatch_release(dispatchObj_channel_);
|
||||
else if (dispatchObj_source_) dispatch_release(dispatchObj_source_);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isConnected {
|
||||
return connState_ == kConnStateConnecting || connState_ == kConnStateConnected;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isListening {
|
||||
return connState_ == kConnStateListening;
|
||||
}
|
||||
|
||||
|
||||
- (id)userInfo {
|
||||
return objc_getAssociatedObject(self, (void*)&kUserInfoKey);
|
||||
}
|
||||
|
||||
- (void)setUserInfo:(id)userInfo {
|
||||
objc_setAssociatedObject(self, (const void*)&kUserInfoKey, userInfo, OBJC_ASSOCIATION_RETAIN);
|
||||
}
|
||||
|
||||
|
||||
- (void)setConnState:(char)connState {
|
||||
connState_ = connState;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDispatchChannel:(dispatch_io_t)channel {
|
||||
assert(connState_ == kConnStateConnecting || connState_ == kConnStateConnected || connState_ == kConnStateNone);
|
||||
dispatch_io_t prevChannel = dispatchObj_channel_;
|
||||
if (prevChannel != channel) {
|
||||
dispatchObj_channel_ = channel;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchObj_channel_) dispatch_retain(dispatchObj_channel_);
|
||||
if (prevChannel) dispatch_release(prevChannel);
|
||||
#endif
|
||||
if (!dispatchObj_channel_ && !dispatchObj_source_) {
|
||||
connState_ = kConnStateNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)setDispatchSource:(dispatch_source_t)source {
|
||||
assert(connState_ == kConnStateListening || connState_ == kConnStateNone);
|
||||
dispatch_source_t prevSource = dispatchObj_source_;
|
||||
if (prevSource != source) {
|
||||
dispatchObj_source_ = source;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchObj_source_) dispatch_retain(dispatchObj_source_);
|
||||
if (prevSource) dispatch_release(prevSource);
|
||||
#endif
|
||||
if (!dispatchObj_channel_ && !dispatchObj_source_) {
|
||||
connState_ = kConnStateNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (id<Lookin_PTChannelDelegate>)delegate {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDelegate:(id<Lookin_PTChannelDelegate>)delegate {
|
||||
delegate_ = delegate;
|
||||
delegateFlags_ = 0;
|
||||
if (!delegate_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([delegate respondsToSelector:@selector(ioFrameChannel:shouldAcceptFrameOfType:tag:payloadSize:)]) {
|
||||
delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize;
|
||||
}
|
||||
|
||||
if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didEndWithError:)]) {
|
||||
delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didEndWithError;
|
||||
}
|
||||
|
||||
if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didAcceptConnection:fromAddress:)]) {
|
||||
delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)debugTag {
|
||||
NSString *state = @"";
|
||||
if (connState_ == kConnStateNone) {
|
||||
state = @"None";
|
||||
} else if (connState_ == kConnStateConnecting) {
|
||||
state = @"Connecting";
|
||||
} else if (connState_ == kConnStateConnected) {
|
||||
state = @"Connected";
|
||||
} else if (connState_ == kConnStateListening) {
|
||||
state = @"Listening";
|
||||
} else {
|
||||
state = @"Undefined";
|
||||
}
|
||||
return [NSString stringWithFormat:@"[%@-%@,%@]", @(self.uniqueID), @(self.targetPort), state];
|
||||
}
|
||||
|
||||
|
||||
//- (void)setFileDescriptor:(dispatch_fd_t)fd {
|
||||
// [self setDispatchChannel:dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
|
||||
// close(fd);
|
||||
// })];
|
||||
//}
|
||||
|
||||
|
||||
#pragma mark - Connecting
|
||||
|
||||
|
||||
- (void)connectToPort:(int)port overUSBHub:(Lookin_PTUSBHub*)usbHub deviceID:(NSNumber*)deviceID callback:(void(^)(NSError *error))callback {
|
||||
assert(protocol_ != NULL);
|
||||
if (connState_ != kConnStateNone) {
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
connState_ = kConnStateConnecting;
|
||||
[usbHub connectToDevice:deviceID port:port onStart:^(NSError *err, dispatch_io_t dispatchChannel) {
|
||||
NSError *error = err;
|
||||
if (!error) {
|
||||
[self startReadingFromConnectedChannel:dispatchChannel error:&error];
|
||||
} else {
|
||||
self->connState_ = kConnStateNone;
|
||||
}
|
||||
if (callback) callback(error);
|
||||
} onEnd:^(NSError *error) {
|
||||
if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
|
||||
[self->delegate_ ioFrameChannel:self didEndWithError:error];
|
||||
}
|
||||
self->endError_ = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)connectToPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error, Lookin_PTAddress *address))callback {
|
||||
assert(protocol_ != NULL);
|
||||
if (connState_ != kConnStateNone) {
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
connState_ = kConnStateConnecting;
|
||||
|
||||
int error = 0;
|
||||
|
||||
// Create socket
|
||||
dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
perror("socket(AF_INET, SOCK_STREAM, 0) failed");
|
||||
error = errno;
|
||||
if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect socket
|
||||
struct sockaddr_in addr;
|
||||
bzero((char *)&addr, sizeof(addr));
|
||||
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
//addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
//addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_addr.s_addr = htonl(address);
|
||||
|
||||
// prevent SIGPIPE
|
||||
int on = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
|
||||
|
||||
// int socket, const struct sockaddr *address, socklen_t address_len
|
||||
if (connect(fd, (const struct sockaddr *)&addr, addr.sin_len) == -1) {
|
||||
//perror("connect");
|
||||
error = errno;
|
||||
close(fd);
|
||||
if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// get actual address
|
||||
//if (getsockname(fd, (struct sockaddr*)&addr, (socklen_t*)&addr.sin_len) == -1) {
|
||||
// error = errno;
|
||||
// close(fd);
|
||||
// if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
|
||||
// return;
|
||||
//}
|
||||
|
||||
dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
|
||||
close(fd);
|
||||
if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
|
||||
NSError *err = error == 0 ? self->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
|
||||
[self->delegate_ ioFrameChannel:self didEndWithError:err];
|
||||
self->endError_ = nil;
|
||||
}
|
||||
});
|
||||
|
||||
if (!dispatchChannel) {
|
||||
close(fd);
|
||||
if (callback) callback([[NSError alloc] initWithDomain:@"PTError" code:0 userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Success
|
||||
NSError *err = nil;
|
||||
Lookin_PTAddress *ptAddr = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
|
||||
[self startReadingFromConnectedChannel:dispatchChannel error:&err];
|
||||
if (callback) callback(err, ptAddr);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Listening and serving
|
||||
|
||||
|
||||
- (void)listenOnPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error))callback {
|
||||
assert(dispatchObj_source_ == nil);
|
||||
|
||||
// Create socket
|
||||
dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect socket
|
||||
struct sockaddr_in addr;
|
||||
bzero((char *)&addr, sizeof(addr));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
//addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
//addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_addr.s_addr = htonl(address);
|
||||
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
int on = 1;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
||||
close(fd);
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
close(fd);
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr*)&addr, socklen) != 0) {
|
||||
close(fd);
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(fd, 512) != 0) {
|
||||
close(fd);
|
||||
if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
|
||||
return;
|
||||
}
|
||||
|
||||
[self setDispatchSource:dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, protocol_.queue)];
|
||||
|
||||
dispatch_source_set_event_handler(dispatchObj_source_, ^{
|
||||
unsigned long nconns = dispatch_source_get_data(self->dispatchObj_source_);
|
||||
while ([self acceptIncomingConnection:fd] && --nconns);
|
||||
});
|
||||
|
||||
dispatch_source_set_cancel_handler(dispatchObj_source_, ^{
|
||||
// Captures *self*, effectively holding a reference to *self* until cancelled.
|
||||
self->dispatchObj_source_ = nil;
|
||||
close(fd);
|
||||
if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
|
||||
[self->delegate_ ioFrameChannel:self didEndWithError:self->endError_];
|
||||
self->endError_ = nil;
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_resume(dispatchObj_source_);
|
||||
//NSLog(@"%@ opened on fd #%d", self, fd);
|
||||
|
||||
connState_ = kConnStateListening;
|
||||
if (callback) callback(nil);
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrLen = sizeof(addr);
|
||||
dispatch_fd_t clientSocketFD = accept(serverSocketFD, (struct sockaddr*)&addr, &addrLen);
|
||||
|
||||
if (clientSocketFD == -1) {
|
||||
perror("accept()");
|
||||
return NO;
|
||||
}
|
||||
|
||||
// prevent SIGPIPE
|
||||
int on = 1;
|
||||
setsockopt(clientSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
|
||||
|
||||
if (fcntl(clientSocketFD, F_SETFL, O_NONBLOCK) == -1) {
|
||||
perror("fcntl(.. O_NONBLOCK)");
|
||||
close(clientSocketFD);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress) {
|
||||
Lookin_PTChannel *peerChannel = [[Lookin_PTChannel alloc] initWithProtocol:protocol_ delegate:delegate_];
|
||||
__block Lookin_PTChannel *localChannelRef = self;
|
||||
dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, clientSocketFD, protocol_.queue, ^(int error) {
|
||||
// Important note: This block captures *self*, thus a reference is held to
|
||||
// *self* until the fd is truly closed.
|
||||
localChannelRef = nil;
|
||||
|
||||
close(clientSocketFD);
|
||||
|
||||
if (peerChannel->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
|
||||
NSError *err = error == 0 ? peerChannel->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
|
||||
[peerChannel->delegate_ ioFrameChannel:peerChannel didEndWithError:err];
|
||||
peerChannel->endError_ = nil;
|
||||
}
|
||||
});
|
||||
|
||||
[peerChannel setConnState:kConnStateConnected];
|
||||
[peerChannel setDispatchChannel:dispatchChannel];
|
||||
|
||||
assert(((struct sockaddr_storage*)&addr)->ss_len == addrLen);
|
||||
Lookin_PTAddress *address = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
|
||||
[delegate_ ioFrameChannel:self didAcceptConnection:peerChannel fromAddress:address];
|
||||
|
||||
NSError *err = nil;
|
||||
if (![peerChannel startReadingFromConnectedChannel:dispatchChannel error:&err]) {
|
||||
// NSLog(@"startReadingFromConnectedChannel failed in accept: %@", err);
|
||||
}
|
||||
} else {
|
||||
close(clientSocketFD);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Closing the channel
|
||||
|
||||
|
||||
- (void)close {
|
||||
// NSLog(@"LookinServer - Will close chanel: %@", self.debugTag);
|
||||
|
||||
if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
|
||||
dispatch_io_close(dispatchObj_channel_, DISPATCH_IO_STOP);
|
||||
[self setDispatchChannel:NULL];
|
||||
} else if (connState_ == kConnStateListening && dispatchObj_source_) {
|
||||
dispatch_source_cancel(dispatchObj_source_);
|
||||
}
|
||||
}
|
||||
|
||||
/// 曾经连接上 Client,然后 Client 端关闭时,Peertalk 内部会对之前 connect 的 channel 调用该方法
|
||||
- (void)cancel {
|
||||
// NSLog(@"LookinServer - Will cancel chanel: %@", self.debugTag);
|
||||
|
||||
if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
|
||||
dispatch_io_close(dispatchObj_channel_, 0);
|
||||
[self setDispatchChannel:NULL];
|
||||
} else if (connState_ == kConnStateListening && dispatchObj_source_) {
|
||||
dispatch_source_cancel(dispatchObj_source_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Reading
|
||||
|
||||
|
||||
- (BOOL)startReadingFromConnectedChannel:(dispatch_io_t)channel error:(__autoreleasing NSError**)error {
|
||||
if (connState_ != kConnStateNone && connState_ != kConnStateConnecting && connState_ != kConnStateConnected) {
|
||||
if (error) *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (dispatchObj_channel_ != channel) {
|
||||
[self close];
|
||||
[self setDispatchChannel:channel];
|
||||
}
|
||||
|
||||
connState_ = kConnStateConnected;
|
||||
|
||||
// helper
|
||||
BOOL(^handleError)(NSError*,BOOL) = ^BOOL(NSError *error, BOOL isEOS) {
|
||||
if (error) {
|
||||
//NSLog(@"Error while communicating: %@", error);
|
||||
self->endError_ = error;
|
||||
[self close];
|
||||
return YES;
|
||||
} else if (isEOS) {
|
||||
[self cancel];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
};
|
||||
|
||||
[protocol_ readFramesOverChannel:channel onFrame:^(NSError *error, uint32_t type, uint32_t tag, uint32_t payloadSize, dispatch_block_t resumeReadingFrames) {
|
||||
if (handleError(error, type == PTFrameTypeEndOfStream)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL accepted = (channel == self->dispatchObj_channel_);
|
||||
if (accepted && (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize)) {
|
||||
accepted = [self->delegate_ ioFrameChannel:self shouldAcceptFrameOfType:type tag:tag payloadSize:payloadSize];
|
||||
}
|
||||
|
||||
if (payloadSize == 0) {
|
||||
if (accepted && self->delegate_) {
|
||||
[self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:nil];
|
||||
} else {
|
||||
// simply ignore the frame
|
||||
}
|
||||
resumeReadingFrames();
|
||||
} else {
|
||||
// has payload
|
||||
if (!accepted) {
|
||||
// Read and discard payload, ignoring frame
|
||||
[self->protocol_ readAndDiscardDataOfSize:payloadSize overChannel:channel callback:^(NSError *error, BOOL endOfStream) {
|
||||
if (!handleError(error, endOfStream)) {
|
||||
resumeReadingFrames();
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[self->protocol_ readPayloadOfSize:payloadSize overChannel:channel callback:^(NSError *error, dispatch_data_t contiguousData, const uint8_t *buffer, size_t bufferSize) {
|
||||
if (handleError(error, bufferSize == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->delegate_) {
|
||||
Lookin_PTData *payload = [[Lookin_PTData alloc] initWithMappedDispatchData:contiguousData data:(void*)buffer length:bufferSize];
|
||||
[self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:payload];
|
||||
}
|
||||
|
||||
resumeReadingFrames();
|
||||
}];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Sending
|
||||
|
||||
- (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback {
|
||||
if (connState_ == kConnStateConnecting || connState_ == kConnStateConnected) {
|
||||
[protocol_ sendFrameOfType:frameType tag:tag withPayload:payload overChannel:dispatchObj_channel_ callback:callback];
|
||||
} else if (callback) {
|
||||
callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (NSString*)description {
|
||||
id userInfo = objc_getAssociatedObject(self, (void*)&kUserInfoKey);
|
||||
return [NSString stringWithFormat:@"<Lookin_PTChannel: %p (%@)%s%@>", self, ( connState_ == kConnStateConnecting ? @"connecting"
|
||||
: connState_ == kConnStateConnected ? @"connected"
|
||||
: connState_ == kConnStateListening ? @"listening"
|
||||
: @"closed"),
|
||||
userInfo ? " " : "", userInfo ? userInfo : @""];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -
|
||||
@implementation Lookin_PTAddress
|
||||
|
||||
- (id)initWithSockaddr:(const struct sockaddr_storage*)addr {
|
||||
if (!(self = [super init])) return nil;
|
||||
assert(addr);
|
||||
memcpy((void*)&sockaddr_, (const void*)addr, addr->ss_len);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)name {
|
||||
if (sockaddr_.ss_len) {
|
||||
const void *sin_addr = NULL;
|
||||
size_t bufsize = 0;
|
||||
if (sockaddr_.ss_family == AF_INET6) {
|
||||
bufsize = INET6_ADDRSTRLEN;
|
||||
sin_addr = (const void *)&((const struct sockaddr_in6*)&sockaddr_)->sin6_addr;
|
||||
} else {
|
||||
bufsize = INET_ADDRSTRLEN;
|
||||
sin_addr = (const void *)&((const struct sockaddr_in*)&sockaddr_)->sin_addr;
|
||||
}
|
||||
char *buf = CFAllocatorAllocate(kCFAllocatorDefault, bufsize+1, 0);
|
||||
if (inet_ntop(sockaddr_.ss_family, sin_addr, buf, (unsigned int)bufsize-1) == NULL) {
|
||||
CFAllocatorDeallocate(kCFAllocatorDefault, buf);
|
||||
return nil;
|
||||
}
|
||||
return [[NSString alloc] initWithBytesNoCopy:(void*)buf length:strlen(buf) encoding:NSUTF8StringEncoding freeWhenDone:YES];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)port {
|
||||
if (sockaddr_.ss_len) {
|
||||
return ntohs(PT_SOCKADDR_ACCESS(&sockaddr_, sin_port, sin6_port));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)description {
|
||||
if (sockaddr_.ss_len) {
|
||||
return [NSString stringWithFormat:@"%@:%u", self.name, (unsigned)self.port];
|
||||
} else {
|
||||
return @"(?)";
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -
|
||||
@implementation Lookin_PTData
|
||||
|
||||
@synthesize dispatchData = dispatchData_;
|
||||
@synthesize data = data_;
|
||||
@synthesize length = length_;
|
||||
|
||||
- (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length {
|
||||
if (!(self = [super init])) return nil;
|
||||
dispatchData_ = mappedContiguousData;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchData_) dispatch_retain(dispatchData_);
|
||||
#endif
|
||||
data_ = data;
|
||||
length_ = length;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchData_) dispatch_release(dispatchData_);
|
||||
#endif
|
||||
data_ = NULL;
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (NSString*)description {
|
||||
return [NSString stringWithFormat:@"<Lookin_PTData: %p (%zu bytes)>", self, length_];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
20
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTPrivate.h
generated
Normal file
20
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTPrivate.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
|
||||
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (!defined(__IPHONE_6_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0)) || \
|
||||
(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (!defined(__MAC_10_8) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8))
|
||||
#define PT_DISPATCH_RETAIN_RELEASE 1
|
||||
#else
|
||||
#define PT_DISPATCH_RETAIN_RELEASE 0
|
||||
#endif
|
||||
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
#define PT_PRECISE_LIFETIME
|
||||
#define PT_PRECISE_LIFETIME_UNUSED
|
||||
#else
|
||||
#define PT_PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
|
||||
#define PT_PRECISE_LIFETIME_UNUSED __attribute__((objc_precise_lifetime, unused))
|
||||
#endif
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
122
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTProtocol.h
generated
Normal file
122
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTProtocol.h
generated
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
|
||||
|
||||
//
|
||||
// A universal frame-based communication protocol which can be used to exchange
|
||||
// arbitrary structured data.
|
||||
//
|
||||
// In short:
|
||||
//
|
||||
// - Each transmission is comprised by one fixed-size frame.
|
||||
// - Each frame contains a protocol version number.
|
||||
// - Each frame contains an application frame type.
|
||||
// - Each frame can contain an identifying tag.
|
||||
// - Each frame can have application-specific data of up to UINT32_MAX size.
|
||||
// - Transactions style messaging can be modeled on top using frame tags.
|
||||
// - Lightweight API on top of libdispatch (aka GCD) -- close to the metal.
|
||||
//
|
||||
#include <dispatch/dispatch.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Special frame tag that signifies "no tag". Your implementation should never
|
||||
// create a reply for a frame with this tag.
|
||||
static const uint32_t PTFrameNoTag = 0;
|
||||
|
||||
// Special frame type that signifies that the stream has ended.
|
||||
static const uint32_t PTFrameTypeEndOfStream = 0;
|
||||
|
||||
// NSError domain
|
||||
FOUNDATION_EXPORT NSString * const Lookin_PTProtocolErrorDomain;
|
||||
|
||||
|
||||
@interface Lookin_PTProtocol : NSObject
|
||||
|
||||
// Queue on which to run data processing blocks.
|
||||
@property dispatch_queue_t queue;
|
||||
|
||||
// Get the shared protocol object for *queue*
|
||||
+ (Lookin_PTProtocol*)sharedProtocolForQueue:(dispatch_queue_t)queue;
|
||||
|
||||
// Initialize a new protocol object to use a specific queue.
|
||||
- (id)initWithDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
// Initialize a new protocol object to use the current calling queue.
|
||||
- (id)init;
|
||||
|
||||
#pragma mark Sending frames
|
||||
|
||||
// Generate a new tag that is unique within this protocol object.
|
||||
- (uint32_t)newTag;
|
||||
|
||||
// Send a frame over *channel* with an optional payload and optional callback.
|
||||
// If *callback* is not NULL, the block is invoked when either an error occured
|
||||
// or when the frame (and payload, if any) has been completely sent.
|
||||
- (void)sendFrameOfType:(uint32_t)frameType
|
||||
tag:(uint32_t)tag
|
||||
withPayload:(dispatch_data_t)payload
|
||||
overChannel:(dispatch_io_t)channel
|
||||
callback:(void(^)(NSError *error))callback;
|
||||
|
||||
#pragma mark Receiving frames
|
||||
|
||||
// Read frames over *channel* as they arrive.
|
||||
// The onFrame handler is responsible for reading (or discarding) any payload
|
||||
// and call *resumeReadingFrames* afterwards to resume reading frames.
|
||||
// To stop reading frames, simply do not invoke *resumeReadingFrames*.
|
||||
// When the stream ends, a frame of type PTFrameTypeEndOfStream is received.
|
||||
- (void)readFramesOverChannel:(dispatch_io_t)channel
|
||||
onFrame:(void(^)(NSError *error,
|
||||
uint32_t type,
|
||||
uint32_t tag,
|
||||
uint32_t payloadSize,
|
||||
dispatch_block_t resumeReadingFrames))onFrame;
|
||||
|
||||
// Read a single frame over *channel*. A frame of type PTFrameTypeEndOfStream
|
||||
// denotes the stream has ended.
|
||||
- (void)readFrameOverChannel:(dispatch_io_t)channel
|
||||
callback:(void(^)(NSError *error,
|
||||
uint32_t frameType,
|
||||
uint32_t frameTag,
|
||||
uint32_t payloadSize))callback;
|
||||
|
||||
#pragma mark Receiving frame payloads
|
||||
|
||||
// Read a complete payload. It's the callers responsibility to make sure
|
||||
// payloadSize is not too large since memory will be automatically allocated
|
||||
// where only payloadSize is the limit.
|
||||
// The returned dispatch_data_t object owns *buffer* and thus you need to call
|
||||
// dispatch_retain on *contiguousData* if you plan to keep *buffer* around after
|
||||
// returning from the callback.
|
||||
- (void)readPayloadOfSize:(size_t)payloadSize
|
||||
overChannel:(dispatch_io_t)channel
|
||||
callback:(void(^)(NSError *error,
|
||||
dispatch_data_t contiguousData,
|
||||
const uint8_t *buffer,
|
||||
size_t bufferSize))callback;
|
||||
|
||||
// Discard data of *size* waiting on *channel*. *callback* can be NULL.
|
||||
- (void)readAndDiscardDataOfSize:(size_t)size
|
||||
overChannel:(dispatch_io_t)channel
|
||||
callback:(void(^)(NSError *error, BOOL endOfStream))callback;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSData (Lookin_PTProtocol)
|
||||
// Creates a new dispatch_data_t object which references the receiver and uses
|
||||
// the receivers bytes as its backing data. The returned dispatch_data_t object
|
||||
// holds a reference to the recevier. It's the callers responsibility to call
|
||||
// dispatch_release on the returned object when done.
|
||||
- (dispatch_data_t)createReferencingDispatchData;
|
||||
+ (NSData *)dataWithContentsOfDispatchData:(dispatch_data_t)data;
|
||||
@end
|
||||
|
||||
@interface NSDictionary (Lookin_PTProtocol)
|
||||
// See description of -[NSData(Lookin_PTProtocol) createReferencingDispatchData]
|
||||
- (dispatch_data_t)createReferencingDispatchData;
|
||||
|
||||
// Decode *data* as a peroperty list-encoded dictionary. Returns nil on failure.
|
||||
+ (NSDictionary*)dictionaryWithContentsOfDispatchData:(dispatch_data_t)data;
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
428
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTProtocol.m
generated
Normal file
428
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTProtocol.m
generated
Normal file
@@ -0,0 +1,428 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
#import "Lookin_PTProtocol.h"
|
||||
#import "Lookin_PTPrivate.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const uint32_t PTProtocolVersion1 = 1;
|
||||
|
||||
NSString * const Lookin_PTProtocolErrorDomain = @"PTProtocolError";
|
||||
|
||||
// This is what we send as the header for each frame.
|
||||
typedef struct _PTFrame {
|
||||
// The version of the frame and protocol.
|
||||
uint32_t version;
|
||||
|
||||
// Type of frame
|
||||
uint32_t type;
|
||||
|
||||
// Unless zero, a tag is retained in frames that are responses to previous
|
||||
// frames. Applications can use this to build transactions or request-response
|
||||
// logic.
|
||||
uint32_t tag;
|
||||
|
||||
// If payloadSize is larger than zero, *payloadSize* number of bytes are
|
||||
// following, constituting application-specific data.
|
||||
uint32_t payloadSize;
|
||||
|
||||
} PTFrame;
|
||||
|
||||
|
||||
@interface Lookin_PTProtocol () {
|
||||
uint32_t nextFrameTag_;
|
||||
@public
|
||||
dispatch_queue_t queue_;
|
||||
}
|
||||
- (dispatch_data_t)createDispatchDataWithFrameOfType:(uint32_t)type frameTag:(uint32_t)frameTag payload:(dispatch_data_t)payload;
|
||||
@end
|
||||
|
||||
|
||||
static void _release_queue_local_protocol(void *objcobj) {
|
||||
if (objcobj) {
|
||||
Lookin_PTProtocol *protocol = (__bridge_transfer id)objcobj;
|
||||
protocol->queue_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@interface Lookin_RQueueLocalIOFrameProtocol : Lookin_PTProtocol
|
||||
@end
|
||||
@implementation Lookin_RQueueLocalIOFrameProtocol
|
||||
- (void)setQueue:(dispatch_queue_t)queue {
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation Lookin_PTProtocol
|
||||
|
||||
|
||||
+ (Lookin_PTProtocol*)sharedProtocolForQueue:(dispatch_queue_t)queue {
|
||||
static const char currentQueueFrameProtocolKey;
|
||||
//dispatch_queue_t queue = dispatch_get_current_queue();
|
||||
Lookin_PTProtocol *currentQueueFrameProtocol = (__bridge Lookin_PTProtocol*)dispatch_queue_get_specific(queue, ¤tQueueFrameProtocolKey);
|
||||
if (!currentQueueFrameProtocol) {
|
||||
currentQueueFrameProtocol = [[Lookin_RQueueLocalIOFrameProtocol alloc] initWithDispatchQueue:NULL];
|
||||
currentQueueFrameProtocol->queue_ = queue; // reference, no retain, since we would create cyclic references
|
||||
dispatch_queue_set_specific(queue, ¤tQueueFrameProtocolKey, (__bridge_retained void*)currentQueueFrameProtocol, &_release_queue_local_protocol);
|
||||
return (__bridge Lookin_PTProtocol*)dispatch_queue_get_specific(queue, ¤tQueueFrameProtocolKey); // to avoid race conds
|
||||
} else {
|
||||
return currentQueueFrameProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithDispatchQueue:(dispatch_queue_t)queue {
|
||||
if (!(self = [super init])) return nil;
|
||||
queue_ = queue;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (queue_) dispatch_retain(queue_);
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithDispatchQueue:dispatch_get_main_queue()];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (queue_) {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(queue_);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)queue {
|
||||
return queue_;
|
||||
}
|
||||
|
||||
- (void)setQueue:(dispatch_queue_t)queue {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_queue_t prev_queue = queue_;
|
||||
queue_ = queue;
|
||||
if (queue_) dispatch_retain(queue_);
|
||||
if (prev_queue) dispatch_release(prev_queue);
|
||||
#else
|
||||
queue_ = queue;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (uint32_t)newTag {
|
||||
return ++nextFrameTag_;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Creating frames
|
||||
|
||||
|
||||
- (dispatch_data_t)createDispatchDataWithFrameOfType:(uint32_t)type frameTag:(uint32_t)frameTag payload:(dispatch_data_t)payload {
|
||||
PTFrame *frame = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(PTFrame), 0);
|
||||
frame->version = htonl(PTProtocolVersion1);
|
||||
frame->type = htonl(type);
|
||||
frame->tag = htonl(frameTag);
|
||||
|
||||
if (payload) {
|
||||
size_t payloadSize = dispatch_data_get_size(payload);
|
||||
assert(payloadSize <= UINT32_MAX);
|
||||
frame->payloadSize = htonl((uint32_t)payloadSize);
|
||||
} else {
|
||||
frame->payloadSize = 0;
|
||||
}
|
||||
|
||||
dispatch_data_t frameData = dispatch_data_create((const void*)frame, sizeof(PTFrame), queue_, ^{
|
||||
CFAllocatorDeallocate(kCFAllocatorDefault, (void*)frame);
|
||||
});
|
||||
|
||||
if (payload && frame->payloadSize != 0) {
|
||||
// chain frame + payload
|
||||
dispatch_data_t data = dispatch_data_create_concat(frameData, payload);
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(frameData);
|
||||
#endif
|
||||
frameData = data;
|
||||
}
|
||||
|
||||
return frameData;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Sending frames
|
||||
|
||||
|
||||
- (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload overChannel:(dispatch_io_t)channel callback:(void(^)(NSError*))callback {
|
||||
dispatch_data_t frame = [self createDispatchDataWithFrameOfType:frameType frameTag:tag payload:payload];
|
||||
dispatch_io_write(channel, 0, frame, queue_, ^(bool done, dispatch_data_t data, int _errno) {
|
||||
if (done && callback) {
|
||||
callback(_errno == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil]);
|
||||
}
|
||||
});
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Receiving frames
|
||||
|
||||
|
||||
- (void)readFrameOverChannel:(dispatch_io_t)channel callback:(void(^)(NSError *error, uint32_t frameType, uint32_t frameTag, uint32_t payloadSize))callback {
|
||||
__block dispatch_data_t allData = NULL;
|
||||
|
||||
dispatch_io_read(channel, 0, sizeof(PTFrame), queue_, ^(bool done, dispatch_data_t data, int error) {
|
||||
//NSLog(@"dispatch_io_read: done=%d data=%p error=%d", done, data, error);
|
||||
size_t dataSize = data ? dispatch_data_get_size(data) : 0;
|
||||
|
||||
if (dataSize) {
|
||||
if (!allData) {
|
||||
allData = data;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_retain(allData);
|
||||
#endif
|
||||
} else {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_data_t allDataPrev = allData;
|
||||
allData = dispatch_data_create_concat(allData, data);
|
||||
dispatch_release(allDataPrev);
|
||||
#else
|
||||
allData = dispatch_data_create_concat(allData, data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
if (error != 0) {
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataSize == 0) {
|
||||
callback(nil, PTFrameTypeEndOfStream, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allData || dispatch_data_get_size(allData) < sizeof(PTFrame)) {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (allData) dispatch_release(allData);
|
||||
#endif
|
||||
callback([[NSError alloc] initWithDomain:Lookin_PTProtocolErrorDomain code:0 userInfo:nil], 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
PTFrame *frame = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(allData, (const void **)&frame, &size); // precise lifetime guarantees bytes in frame will stay valid till the end of scope
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(allData);
|
||||
#endif
|
||||
if (!contiguousData) {
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:ENOMEM userInfo:nil], 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
frame->version = ntohl(frame->version);
|
||||
if (frame->version != PTProtocolVersion1) {
|
||||
callback([[NSError alloc] initWithDomain:Lookin_PTProtocolErrorDomain code:0 userInfo:nil], 0, 0, 0);
|
||||
} else {
|
||||
frame->type = ntohl(frame->type);
|
||||
frame->tag = ntohl(frame->tag);
|
||||
frame->payloadSize = ntohl(frame->payloadSize);
|
||||
callback(nil, frame->type, frame->tag, frame->payloadSize);
|
||||
}
|
||||
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(contiguousData);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)readPayloadOfSize:(size_t)payloadSize overChannel:(dispatch_io_t)channel callback:(void(^)(NSError *error, dispatch_data_t contiguousData, const uint8_t *buffer, size_t bufferSize))callback {
|
||||
__block dispatch_data_t allData = NULL;
|
||||
dispatch_io_read(channel, 0, payloadSize, queue_, ^(bool done, dispatch_data_t data, int error) {
|
||||
//NSLog(@"dispatch_io_read: done=%d data=%p error=%d", done, data, error);
|
||||
size_t dataSize = dispatch_data_get_size(data);
|
||||
|
||||
if (dataSize) {
|
||||
if (!allData) {
|
||||
allData = data;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_retain(allData);
|
||||
#endif
|
||||
} else {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_data_t allDataPrev = allData;
|
||||
allData = dispatch_data_create_concat(allData, data);
|
||||
dispatch_release(allDataPrev);
|
||||
#else
|
||||
allData = dispatch_data_create_concat(allData, data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
if (error != 0) {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (allData) dispatch_release(allData);
|
||||
#endif
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataSize == 0) {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (allData) dispatch_release(allData);
|
||||
#endif
|
||||
callback(nil, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buffer = NULL;
|
||||
size_t bufferSize = 0;
|
||||
PT_PRECISE_LIFETIME dispatch_data_t contiguousData = NULL;
|
||||
|
||||
if (allData) {
|
||||
contiguousData = dispatch_data_create_map(allData, (const void **)&buffer, &bufferSize);
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(allData); allData = NULL;
|
||||
#endif
|
||||
if (!contiguousData) {
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:ENOMEM userInfo:nil], NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback(nil, contiguousData, buffer, bufferSize);
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (contiguousData) dispatch_release(contiguousData);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)readAndDiscardDataOfSize:(size_t)size overChannel:(dispatch_io_t)channel callback:(void(^)(NSError*, BOOL))callback {
|
||||
dispatch_io_read(channel, 0, size, queue_, ^(bool done, dispatch_data_t data, int error) {
|
||||
if (done && callback) {
|
||||
size_t dataSize = data ? dispatch_data_get_size(data) : 0;
|
||||
callback(error == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], dataSize == 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)readFramesOverChannel:(dispatch_io_t)channel onFrame:(void(^)(NSError*, uint32_t, uint32_t, uint32_t, dispatch_block_t))onFrame {
|
||||
[self readFrameOverChannel:channel callback:^(NSError *error, uint32_t type, uint32_t tag, uint32_t payloadSize) {
|
||||
onFrame(error, type, tag, payloadSize, ^{
|
||||
if (type != PTFrameTypeEndOfStream) {
|
||||
[self readFramesOverChannel:channel onFrame:onFrame];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface Lookin_PTDispatchData : NSObject {
|
||||
dispatch_data_t dispatchData_;
|
||||
}
|
||||
@end
|
||||
@implementation Lookin_PTDispatchData
|
||||
- (id)initWithDispatchData:(dispatch_data_t)dispatchData {
|
||||
if (!(self = [super init])) return nil;
|
||||
dispatchData_ = dispatchData;
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_retain(dispatchData_);
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
if (dispatchData_) dispatch_release(dispatchData_);
|
||||
#endif
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSData (Lookin_PTProtocol)
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-getter-return-value"
|
||||
|
||||
- (dispatch_data_t)createReferencingDispatchData {
|
||||
// Note: The queue is used to submit the destructor. Since we only perform an
|
||||
// atomic release of self, it doesn't really matter which queue is used, thus
|
||||
// we use the current calling queue.
|
||||
return dispatch_data_create((const void*)self.bytes, self.length, dispatch_get_main_queue(), ^{
|
||||
// trick to have the block capture the data, thus retain/releasing
|
||||
[self length];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (NSData *)dataWithContentsOfDispatchData:(dispatch_data_t)data {
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
uint8_t *buffer = NULL;
|
||||
size_t bufferSize = 0;
|
||||
PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(data, (const void **)&buffer, &bufferSize);
|
||||
if (!contiguousData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
Lookin_PTDispatchData *dispatchDataRef = [[Lookin_PTDispatchData alloc] initWithDispatchData:contiguousData];
|
||||
NSData *newData = [NSData dataWithBytesNoCopy:(void*)buffer length:bufferSize freeWhenDone:NO];
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(contiguousData);
|
||||
#endif
|
||||
static const bool kDispatchDataRefKey;
|
||||
objc_setAssociatedObject(newData, (const void*)kDispatchDataRefKey, dispatchDataRef, OBJC_ASSOCIATION_RETAIN);
|
||||
|
||||
return newData;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSDictionary (Lookin_PTProtocol)
|
||||
|
||||
- (dispatch_data_t)createReferencingDispatchData {
|
||||
NSError *error = nil;
|
||||
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error];
|
||||
if (!plistData) {
|
||||
NSLog(@"Failed to serialize property list: %@", error);
|
||||
return nil;
|
||||
} else {
|
||||
return [plistData createReferencingDispatchData];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode *data* as a peroperty list-encoded dictionary. Returns nil on failure.
|
||||
+ (NSDictionary*)dictionaryWithContentsOfDispatchData:(dispatch_data_t)data {
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
uint8_t *buffer = NULL;
|
||||
size_t bufferSize = 0;
|
||||
PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(data, (const void **)&buffer, &bufferSize);
|
||||
if (!contiguousData) {
|
||||
return nil;
|
||||
}
|
||||
NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytesNoCopy:(void*)buffer length:bufferSize freeWhenDone:NO] options:NSPropertyListImmutable format:NULL error:nil];
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(contiguousData);
|
||||
#endif
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
88
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTUSBHub.h
generated
Normal file
88
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTUSBHub.h
generated
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Lookin_PTUSBDeviceDidAttachNotification
|
||||
// Posted when a device has been attached. Also posted for each device that is
|
||||
// already attached when the Lookin_PTUSBHub starts listening.
|
||||
//
|
||||
// .userInfo = {
|
||||
// DeviceID = 3;
|
||||
// MessageType = Attached;
|
||||
// Properties = {
|
||||
// ConnectionSpeed = 480000000;
|
||||
// ConnectionType = USB;
|
||||
// DeviceID = 3;
|
||||
// LocationID = 1234567890;
|
||||
// ProductID = 1234;
|
||||
// SerialNumber = 0123456789abcdef0123456789abcdef01234567;
|
||||
// };
|
||||
// }
|
||||
//
|
||||
FOUNDATION_EXPORT NSString * const Lookin_PTUSBDeviceDidAttachNotification;
|
||||
|
||||
// Lookin_PTUSBDeviceDidDetachNotification
|
||||
// Posted when a device has been detached.
|
||||
//
|
||||
// .userInfo = {
|
||||
// DeviceID = 3;
|
||||
// MessageType = Detached;
|
||||
// }
|
||||
//
|
||||
FOUNDATION_EXPORT NSString * const Lookin_PTUSBDeviceDidDetachNotification;
|
||||
|
||||
// NSError domain
|
||||
FOUNDATION_EXPORT NSString * const Lookin_PTUSBHubErrorDomain;
|
||||
|
||||
// Error codes returned with NSError.code for NSError domain Lookin_PTUSBHubErrorDomain
|
||||
typedef enum {
|
||||
PTUSBHubErrorBadDevice = 2,
|
||||
PTUSBHubErrorConnectionRefused = 3,
|
||||
} PTUSBHubError;
|
||||
|
||||
@interface Lookin_PTUSBHub : NSObject
|
||||
|
||||
// Shared, implicitly opened hub.
|
||||
+ (Lookin_PTUSBHub*)sharedHub;
|
||||
|
||||
// Connect to a TCP *port* on a device, while the actual transport is over USB.
|
||||
// Upon success, *error* is nil and *channel* is a duplex I/O channel.
|
||||
// You can retrieve the underlying file descriptor using
|
||||
// dispatch_io_get_descriptor(channel). The dispatch_io_t channel behaves just
|
||||
// like any stream type dispatch_io_t, making it possible to use the same logic
|
||||
// for both USB bridged connections and e.g. ethernet-based connections.
|
||||
//
|
||||
// *onStart* is called either when a connection failed, in which case the error
|
||||
// argument is non-nil, or when the connection was successfully established (the
|
||||
// error argument is nil). Must not be NULL.
|
||||
//
|
||||
// *onEnd* is called when a connection was open and just did close. If the error
|
||||
// argument is non-nil, the channel closed because of an error. Pass NULL for no
|
||||
// callback.
|
||||
//
|
||||
- (void)connectToDevice:(NSNumber*)deviceID
|
||||
port:(int)port
|
||||
onStart:(void(^)(NSError *error, dispatch_io_t channel))onStart
|
||||
onEnd:(void(^)(NSError *error))onEnd;
|
||||
|
||||
// Start listening for devices. You only need to invoke this method on custom
|
||||
// instances to start receiving notifications. The shared instance returned from
|
||||
// +sharedHub is always in listening mode.
|
||||
//
|
||||
// *onStart* is called either when the system failed to start listening, in
|
||||
// which case the error argument is non-nil, or when the receiver is listening.
|
||||
// Pass NULL for no callback.
|
||||
//
|
||||
// *onEnd* is called when listening stopped. If the error argument is non-nil,
|
||||
// listening stopped because of an error. Pass NULL for no callback.
|
||||
//
|
||||
- (void)listenOnQueue:(dispatch_queue_t)queue
|
||||
onStart:(void(^)(NSError*))onStart
|
||||
onEnd:(void(^)(NSError*))onEnd;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
674
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTUSBHub.m
generated
Normal file
674
Pods/LookinServer/Src/Main/Shared/Peertalk/Lookin_PTUSBHub.m
generated
Normal file
@@ -0,0 +1,674 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
#import "Lookin_PTUSBHub.h"
|
||||
|
||||
|
||||
|
||||
#import "Lookin_PTPrivate.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/un.h>
|
||||
#include <err.h>
|
||||
|
||||
NSString * const Lookin_PTUSBHubErrorDomain = @"PTUSBHubError";
|
||||
|
||||
typedef uint32_t USBMuxPacketType;
|
||||
enum {
|
||||
USBMuxPacketTypeResult = 1,
|
||||
USBMuxPacketTypeConnect = 2,
|
||||
USBMuxPacketTypeListen = 3,
|
||||
USBMuxPacketTypeDeviceAdd = 4,
|
||||
USBMuxPacketTypeDeviceRemove = 5,
|
||||
// ? = 6,
|
||||
// ? = 7,
|
||||
USBMuxPacketTypePlistPayload = 8,
|
||||
};
|
||||
|
||||
typedef uint32_t USBMuxPacketProtocol;
|
||||
enum {
|
||||
USBMuxPacketProtocolBinary = 0,
|
||||
USBMuxPacketProtocolPlist = 1,
|
||||
};
|
||||
|
||||
typedef uint32_t USBMuxReplyCode;
|
||||
enum {
|
||||
USBMuxReplyCodeOK = 0,
|
||||
USBMuxReplyCodeBadCommand = 1,
|
||||
USBMuxReplyCodeBadDevice = 2,
|
||||
USBMuxReplyCodeConnectionRefused = 3,
|
||||
// ? = 4,
|
||||
// ? = 5,
|
||||
USBMuxReplyCodeBadVersion = 6,
|
||||
};
|
||||
|
||||
|
||||
typedef struct usbmux_packet {
|
||||
uint32_t size;
|
||||
USBMuxPacketProtocol protocol;
|
||||
USBMuxPacketType type;
|
||||
uint32_t tag;
|
||||
char data[0];
|
||||
} __attribute__((__packed__)) usbmux_packet_t;
|
||||
|
||||
static const uint32_t kUsbmuxPacketMaxPayloadSize = UINT32_MAX - (uint32_t)sizeof(usbmux_packet_t);
|
||||
|
||||
|
||||
static uint32_t usbmux_packet_payload_size(usbmux_packet_t *upacket) {
|
||||
return upacket->size - sizeof(usbmux_packet_t);
|
||||
}
|
||||
|
||||
|
||||
static void *usbmux_packet_payload(usbmux_packet_t *upacket) {
|
||||
return (void*)upacket->data;
|
||||
}
|
||||
|
||||
|
||||
static void usbmux_packet_set_payload(usbmux_packet_t *upacket,
|
||||
const void *payload,
|
||||
uint32_t payloadLength)
|
||||
{
|
||||
memcpy(usbmux_packet_payload(upacket), payload, payloadLength);
|
||||
}
|
||||
|
||||
|
||||
static usbmux_packet_t *usbmux_packet_alloc(uint32_t payloadSize) {
|
||||
assert(payloadSize <= kUsbmuxPacketMaxPayloadSize);
|
||||
uint32_t upacketSize = sizeof(usbmux_packet_t) + payloadSize;
|
||||
usbmux_packet_t *upacket = CFAllocatorAllocate(kCFAllocatorDefault, upacketSize, 0);
|
||||
memset(upacket, 0, sizeof(usbmux_packet_t));
|
||||
upacket->size = upacketSize;
|
||||
return upacket;
|
||||
}
|
||||
|
||||
|
||||
static usbmux_packet_t *usbmux_packet_create(USBMuxPacketProtocol protocol,
|
||||
USBMuxPacketType type,
|
||||
uint32_t tag,
|
||||
const void *payload,
|
||||
uint32_t payloadSize)
|
||||
{
|
||||
usbmux_packet_t *upacket = usbmux_packet_alloc(payloadSize);
|
||||
if (!upacket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
upacket->protocol = protocol;
|
||||
upacket->type = type;
|
||||
upacket->tag = tag;
|
||||
|
||||
if (payload && payloadSize) {
|
||||
usbmux_packet_set_payload(upacket, payload, (uint32_t)payloadSize);
|
||||
}
|
||||
|
||||
return upacket;
|
||||
}
|
||||
|
||||
|
||||
static void usbmux_packet_free(usbmux_packet_t *upacket) {
|
||||
CFAllocatorDeallocate(kCFAllocatorDefault, upacket);
|
||||
}
|
||||
|
||||
|
||||
NSString * const Lookin_PTUSBDeviceDidAttachNotification = @"Lookin_PTUSBDeviceDidAttachNotification";
|
||||
NSString * const Lookin_PTUSBDeviceDidDetachNotification = @"Lookin_PTUSBDeviceDidDetachNotification";
|
||||
|
||||
static NSString *kPlistPacketTypeListen = @"Listen";
|
||||
static NSString *kPlistPacketTypeConnect = @"Connect";
|
||||
|
||||
|
||||
// Represents a channel of communication between the host process and a remote
|
||||
// (device) system. In practice, a Lookin_PTUSBChannel is connected to a usbmuxd
|
||||
// endpoint which is configured to either listen for device changes (the
|
||||
// PTUSBHub's channel is usually configured as a device notification listener) or
|
||||
// configured as a TCP bridge (e.g. channels returned from PTUSBHub's
|
||||
// connectToDevice:port:callback:). You should not create channels yourself, but
|
||||
// let Lookin_PTUSBHub provide you with already configured channels.
|
||||
@interface Lookin_PTUSBChannel : NSObject {
|
||||
dispatch_io_t channel_;
|
||||
dispatch_queue_t queue_;
|
||||
uint32_t nextPacketTag_;
|
||||
NSMutableDictionary *responseQueue_;
|
||||
BOOL autoReadPackets_;
|
||||
BOOL isReadingPackets_;
|
||||
}
|
||||
|
||||
// The underlying dispatch I/O channel. This is handy if you want to handle your
|
||||
// own I/O logic without Lookin_PTUSBChannel. Remember to dispatch_retain() the channel
|
||||
// if you plan on using it as it might be released from the Lookin_PTUSBChannel at any
|
||||
// point in time.
|
||||
@property (readonly) dispatch_io_t dispatchChannel;
|
||||
|
||||
// The underlying file descriptor.
|
||||
@property (readonly) dispatch_fd_t fileDescriptor;
|
||||
|
||||
// Send data
|
||||
- (void)sendDispatchData:(dispatch_data_t)data callback:(void(^)(NSError*))callback;
|
||||
- (void)sendData:(NSData*)data callback:(void(^)(NSError*))callback;
|
||||
|
||||
// Read data
|
||||
- (void)readFromOffset:(off_t)offset length:(size_t)length callback:(void(^)(NSError *error, dispatch_data_t data))callback;
|
||||
|
||||
// Close the channel, preventing further reads and writes, but letting currently
|
||||
// queued reads and writes finish.
|
||||
- (void)cancel;
|
||||
|
||||
// Close the channel, preventing further reads and writes, immediately
|
||||
// terminating any ongoing reads and writes.
|
||||
- (void)stop;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface Lookin_PTUSBChannel (Private)
|
||||
|
||||
+ (NSDictionary*)packetDictionaryWithPacketType:(NSString*)messageType payload:(NSDictionary*)payload;
|
||||
- (BOOL)openOnQueue:(dispatch_queue_t)queue error:(NSError**)error onEnd:(void(^)(NSError *error))onEnd;
|
||||
- (void)listenWithBroadcastHandler:(void(^)(NSDictionary *packet))broadcastHandler callback:(void(^)(NSError*))callback;
|
||||
- (BOOL)errorFromPlistResponse:(NSDictionary*)packet error:(NSError**)error;
|
||||
- (uint32_t)nextPacketTag;
|
||||
- (void)sendPacketOfType:(USBMuxPacketType)type overProtocol:(USBMuxPacketProtocol)protocol tag:(uint32_t)tag payload:(NSData*)payload callback:(void(^)(NSError*))callback;
|
||||
- (void)sendPacket:(NSDictionary*)packet tag:(uint32_t)tag callback:(void(^)(NSError *error))callback;
|
||||
- (void)sendRequest:(NSDictionary*)packet callback:(void(^)(NSError *error, NSDictionary *responsePacket))callback;
|
||||
- (void)scheduleReadPacketWithCallback:(void(^)(NSError *error, NSDictionary *packet, uint32_t packetTag))callback;
|
||||
- (void)scheduleReadPacketWithBroadcastHandler:(void(^)(NSDictionary *packet))broadcastHandler;
|
||||
- (void)setNeedsReadingPacket;
|
||||
@end
|
||||
|
||||
|
||||
@interface Lookin_PTUSBHub () {
|
||||
Lookin_PTUSBChannel *channel_;
|
||||
}
|
||||
- (void)handleBroadcastPacket:(NSDictionary*)packet;
|
||||
@end
|
||||
|
||||
|
||||
@implementation Lookin_PTUSBHub
|
||||
|
||||
|
||||
+ (Lookin_PTUSBHub*)sharedHub {
|
||||
static Lookin_PTUSBHub *gSharedHub;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
gSharedHub = [Lookin_PTUSBHub new];
|
||||
[gSharedHub listenOnQueue:dispatch_get_main_queue() onStart:^(NSError *error) {
|
||||
if (error) {
|
||||
NSLog(@"Lookin_PTUSBHub failed to initialize: %@", error);
|
||||
}
|
||||
} onEnd:nil];
|
||||
});
|
||||
return gSharedHub;
|
||||
}
|
||||
|
||||
|
||||
- (id)init {
|
||||
if (!(self = [super init])) return nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)listenOnQueue:(dispatch_queue_t)queue onStart:(void(^)(NSError*))onStart onEnd:(void(^)(NSError*))onEnd {
|
||||
if (channel_) {
|
||||
if (onStart) onStart(nil);
|
||||
return;
|
||||
}
|
||||
channel_ = [Lookin_PTUSBChannel new];
|
||||
NSError *error = nil;
|
||||
if ([channel_ openOnQueue:queue error:&error onEnd:onEnd]) {
|
||||
[channel_ listenWithBroadcastHandler:^(NSDictionary *packet) { [self handleBroadcastPacket:packet]; } callback:onStart];
|
||||
} else if (onStart) {
|
||||
onStart(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)connectToDevice:(NSNumber*)deviceID port:(int)port onStart:(void(^)(NSError*, dispatch_io_t))onStart onEnd:(void(^)(NSError*))onEnd {
|
||||
Lookin_PTUSBChannel *channel = [Lookin_PTUSBChannel new];
|
||||
NSError *error = nil;
|
||||
|
||||
if (![channel openOnQueue:dispatch_get_main_queue() error:&error onEnd:onEnd]) {
|
||||
onStart(error, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
port = ((port<<8) & 0xFF00) | (port>>8); // limit
|
||||
|
||||
NSDictionary *packet = [Lookin_PTUSBChannel packetDictionaryWithPacketType:kPlistPacketTypeConnect
|
||||
payload:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
deviceID, @"DeviceID",
|
||||
[NSNumber numberWithInt:port], @"PortNumber",
|
||||
nil]];
|
||||
|
||||
[channel sendRequest:packet callback:^(NSError *error_, NSDictionary *responsePacket) {
|
||||
NSError *error = error_;
|
||||
[channel errorFromPlistResponse:responsePacket error:&error];
|
||||
onStart(error, (error ? nil : channel.dispatchChannel) );
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)handleBroadcastPacket:(NSDictionary*)packet {
|
||||
NSString *messageType = [packet objectForKey:@"MessageType"];
|
||||
|
||||
if ([@"Attached" isEqualToString:messageType]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:Lookin_PTUSBDeviceDidAttachNotification object:self userInfo:packet];
|
||||
} else if ([@"Detached" isEqualToString:messageType]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:Lookin_PTUSBDeviceDidDetachNotification object:self userInfo:packet];
|
||||
} else {
|
||||
NSLog(@"Warning: Unhandled broadcast message: %@", packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation Lookin_PTUSBChannel
|
||||
|
||||
+ (NSDictionary*)packetDictionaryWithPacketType:(NSString*)messageType payload:(NSDictionary*)payload {
|
||||
NSDictionary *packet = nil;
|
||||
|
||||
static NSString *bundleName = nil;
|
||||
static NSString *bundleVersion = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSDictionary *infoDict = [NSBundle mainBundle].infoDictionary;
|
||||
if (infoDict) {
|
||||
bundleName = [infoDict objectForKey:@"CFBundleName"];
|
||||
bundleVersion = [[infoDict objectForKey:@"CFBundleVersion"] description];
|
||||
}
|
||||
});
|
||||
|
||||
if (bundleName) {
|
||||
packet = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
messageType, @"MessageType",
|
||||
bundleName, @"ProgName",
|
||||
bundleVersion, @"ClientVersionString",
|
||||
nil];
|
||||
} else {
|
||||
packet = [NSDictionary dictionaryWithObjectsAndKeys:messageType, @"MessageType", nil];
|
||||
}
|
||||
|
||||
if (payload) {
|
||||
NSMutableDictionary *mpacket = [NSMutableDictionary dictionaryWithDictionary:payload];
|
||||
[mpacket addEntriesFromDictionary:packet];
|
||||
packet = mpacket;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
- (id)init {
|
||||
if (!(self = [super init])) return nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
//NSLog(@"dealloc %@", self);
|
||||
if (channel_) {
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(channel_);
|
||||
#endif
|
||||
channel_ = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)valid {
|
||||
return !!channel_;
|
||||
}
|
||||
|
||||
|
||||
- (dispatch_io_t)dispatchChannel {
|
||||
return channel_;
|
||||
}
|
||||
|
||||
|
||||
- (dispatch_fd_t)fileDescriptor {
|
||||
return dispatch_io_get_descriptor(channel_);
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)openOnQueue:(dispatch_queue_t)queue error:(NSError**)error onEnd:(void(^)(NSError*))onEnd {
|
||||
assert(queue != nil);
|
||||
assert(channel_ == nil);
|
||||
queue_ = queue;
|
||||
|
||||
// Create socket
|
||||
dispatch_fd_t fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
if (error) *error = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// prevent SIGPIPE
|
||||
int on = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
|
||||
|
||||
// Connect socket
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
strcpy(addr.sun_path, "/var/run/usbmuxd");
|
||||
socklen_t socklen = sizeof(addr);
|
||||
if (connect(fd, (struct sockaddr*)&addr, socklen) == -1) {
|
||||
if (error) *error = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
|
||||
return NO;
|
||||
}
|
||||
|
||||
channel_ = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue_, ^(int error) {
|
||||
close(fd);
|
||||
if (onEnd) {
|
||||
onEnd(error == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil]);
|
||||
}
|
||||
});
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)listenWithBroadcastHandler:(void(^)(NSDictionary *packet))broadcastHandler callback:(void(^)(NSError*))callback {
|
||||
autoReadPackets_ = YES;
|
||||
[self scheduleReadPacketWithBroadcastHandler:broadcastHandler];
|
||||
|
||||
NSDictionary *packet = [Lookin_PTUSBChannel packetDictionaryWithPacketType:kPlistPacketTypeListen payload:nil];
|
||||
|
||||
[self sendRequest:packet callback:^(NSError *error_, NSDictionary *responsePacket) {
|
||||
if (!callback)
|
||||
return;
|
||||
|
||||
NSError *error = error_;
|
||||
[self errorFromPlistResponse:responsePacket error:&error];
|
||||
|
||||
callback(error);
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)errorFromPlistResponse:(NSDictionary*)packet error:(NSError**)error {
|
||||
if (!*error) {
|
||||
NSNumber *n = [packet objectForKey:@"Number"];
|
||||
|
||||
if (!n) {
|
||||
*error = [NSError errorWithDomain:Lookin_PTUSBHubErrorDomain code:(n ? n.integerValue : 0) userInfo:nil];
|
||||
return NO;
|
||||
}
|
||||
|
||||
USBMuxReplyCode replyCode = (USBMuxReplyCode)n.integerValue;
|
||||
if (replyCode != 0) {
|
||||
NSString *errmessage = @"Unspecified error";
|
||||
switch (replyCode) {
|
||||
case USBMuxReplyCodeBadCommand: errmessage = @"illegal command"; break;
|
||||
case USBMuxReplyCodeBadDevice: errmessage = @"unknown device"; break;
|
||||
case USBMuxReplyCodeConnectionRefused: errmessage = @"connection refused"; break;
|
||||
case USBMuxReplyCodeBadVersion: errmessage = @"invalid version"; break;
|
||||
default: break;
|
||||
}
|
||||
*error = [NSError errorWithDomain:Lookin_PTUSBHubErrorDomain code:replyCode userInfo:[NSDictionary dictionaryWithObject:errmessage forKey:NSLocalizedDescriptionKey]];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (uint32_t)nextPacketTag {
|
||||
return ++nextPacketTag_;
|
||||
}
|
||||
|
||||
|
||||
- (void)sendRequest:(NSDictionary*)packet callback:(void(^)(NSError*, NSDictionary*))callback {
|
||||
uint32_t tag = [self nextPacketTag];
|
||||
[self sendPacket:packet tag:tag callback:^(NSError *error) {
|
||||
if (error) {
|
||||
callback(error, nil);
|
||||
return;
|
||||
}
|
||||
// TODO: timeout un-triggered callbacks in responseQueue_
|
||||
if (!self->responseQueue_) self->responseQueue_ = [NSMutableDictionary new];
|
||||
[self->responseQueue_ setObject:callback forKey:[NSNumber numberWithUnsignedInt:tag]];
|
||||
}];
|
||||
|
||||
// We are awaiting a response
|
||||
[self setNeedsReadingPacket];
|
||||
}
|
||||
|
||||
|
||||
- (void)setNeedsReadingPacket {
|
||||
if (!isReadingPackets_) {
|
||||
[self scheduleReadPacketWithBroadcastHandler:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)scheduleReadPacketWithBroadcastHandler:(void(^)(NSDictionary *packet))broadcastHandler {
|
||||
assert(isReadingPackets_ == NO);
|
||||
|
||||
[self scheduleReadPacketWithCallback:^(NSError *error, NSDictionary *packet, uint32_t packetTag) {
|
||||
// Interpret the package we just received
|
||||
if (packetTag == 0) {
|
||||
// Broadcast message
|
||||
//NSLog(@"Received broadcast: %@", packet);
|
||||
if (broadcastHandler) broadcastHandler(packet);
|
||||
} else if (self->responseQueue_) {
|
||||
// Reply
|
||||
NSNumber *key = [NSNumber numberWithUnsignedInt:packetTag];
|
||||
void(^requestCallback)(NSError*,NSDictionary*) = [self->responseQueue_ objectForKey:key];
|
||||
if (requestCallback) {
|
||||
[self->responseQueue_ removeObjectForKey:key];
|
||||
requestCallback(error, packet);
|
||||
} else {
|
||||
NSLog(@"Warning: Ignoring reply packet for which there is no registered callback. Packet => %@", packet);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule reading another incoming package
|
||||
if (self->autoReadPackets_) {
|
||||
[self scheduleReadPacketWithBroadcastHandler:broadcastHandler];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)scheduleReadPacketWithCallback:(void(^)(NSError*, NSDictionary*, uint32_t))callback {
|
||||
static usbmux_packet_t ref_upacket;
|
||||
isReadingPackets_ = YES;
|
||||
|
||||
// Read the first `sizeof(ref_upacket.size)` bytes off the channel_
|
||||
dispatch_io_read(channel_, 0, sizeof(ref_upacket.size), queue_, ^(bool done, dispatch_data_t data, int error) {
|
||||
//NSLog(@"dispatch_io_read 0,4: done=%d data=%p error=%d", done, data, error);
|
||||
|
||||
if (!done)
|
||||
return;
|
||||
|
||||
if (error) {
|
||||
self->isReadingPackets_ = NO;
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read size of incoming usbmux_packet_t
|
||||
uint32_t upacket_len = 0;
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
PT_PRECISE_LIFETIME_UNUSED dispatch_data_t map_data = dispatch_data_create_map(data, (const void **)&buffer, &buffer_size); // objc_precise_lifetime guarantees 'map_data' isn't released before memcpy has a chance to do its thing
|
||||
assert(buffer_size == sizeof(ref_upacket.size));
|
||||
assert(sizeof(upacket_len) == sizeof(ref_upacket.size));
|
||||
memcpy((void *)&(upacket_len), (const void *)buffer, buffer_size);
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(map_data);
|
||||
#endif
|
||||
|
||||
// Allocate a new usbmux_packet_t for the expected size
|
||||
uint32_t payloadLength = upacket_len - (uint32_t)sizeof(usbmux_packet_t);
|
||||
usbmux_packet_t *upacket = usbmux_packet_alloc(payloadLength);
|
||||
|
||||
// Read rest of the incoming usbmux_packet_t
|
||||
off_t offset = sizeof(ref_upacket.size);
|
||||
dispatch_io_read(self->channel_, offset, (size_t)(upacket->size - offset), self->queue_, ^(bool done, dispatch_data_t data, int error) {
|
||||
//NSLog(@"dispatch_io_read X,Y: done=%d data=%p error=%d", done, data, error);
|
||||
|
||||
if (!done) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->isReadingPackets_ = NO;
|
||||
|
||||
if (error) {
|
||||
callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil, 0);
|
||||
usbmux_packet_free(upacket);
|
||||
return;
|
||||
}
|
||||
|
||||
if (upacket_len > kUsbmuxPacketMaxPayloadSize) {
|
||||
callback(
|
||||
[[NSError alloc] initWithDomain:Lookin_PTUSBHubErrorDomain code:1 userInfo:@{
|
||||
NSLocalizedDescriptionKey:@"Received a packet that is too large"}],
|
||||
nil,
|
||||
0
|
||||
);
|
||||
usbmux_packet_free(upacket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy read bytes onto our usbmux_packet_t
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
PT_PRECISE_LIFETIME_UNUSED dispatch_data_t map_data = dispatch_data_create_map(data, (const void **)&buffer, &buffer_size);
|
||||
assert(buffer_size == upacket->size - offset);
|
||||
memcpy(((void *)(upacket))+offset, (const void *)buffer, buffer_size);
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(map_data);
|
||||
#endif
|
||||
|
||||
// We only support plist protocol
|
||||
if (upacket->protocol != USBMuxPacketProtocolPlist) {
|
||||
callback([[NSError alloc] initWithDomain:Lookin_PTUSBHubErrorDomain code:0 userInfo:[NSDictionary dictionaryWithObject:@"Unexpected package protocol" forKey:NSLocalizedDescriptionKey]], nil, upacket->tag);
|
||||
usbmux_packet_free(upacket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only one type of packet in the plist protocol
|
||||
if (upacket->type != USBMuxPacketTypePlistPayload) {
|
||||
callback([[NSError alloc] initWithDomain:Lookin_PTUSBHubErrorDomain code:0 userInfo:[NSDictionary dictionaryWithObject:@"Unexpected package type" forKey:NSLocalizedDescriptionKey]], nil, upacket->tag);
|
||||
usbmux_packet_free(upacket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to decode any payload as plist
|
||||
NSError *err = nil;
|
||||
NSDictionary *dict = nil;
|
||||
if (usbmux_packet_payload_size(upacket)) {
|
||||
dict = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytesNoCopy:usbmux_packet_payload(upacket) length:usbmux_packet_payload_size(upacket) freeWhenDone:NO] options:NSPropertyListImmutable format:NULL error:&err];
|
||||
}
|
||||
|
||||
// Invoke callback
|
||||
callback(err, dict, upacket->tag);
|
||||
usbmux_packet_free(upacket);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)sendPacketOfType:(USBMuxPacketType)type
|
||||
overProtocol:(USBMuxPacketProtocol)protocol
|
||||
tag:(uint32_t)tag
|
||||
payload:(NSData*)payload
|
||||
callback:(void(^)(NSError*))callback
|
||||
{
|
||||
assert(payload.length <= kUsbmuxPacketMaxPayloadSize);
|
||||
usbmux_packet_t *upacket = usbmux_packet_create(
|
||||
protocol,
|
||||
type,
|
||||
tag,
|
||||
payload ? payload.bytes : nil,
|
||||
(uint32_t)(payload ? payload.length : 0)
|
||||
);
|
||||
dispatch_data_t data = dispatch_data_create((const void*)upacket, upacket->size, queue_, ^{
|
||||
// Free packet when data is freed
|
||||
usbmux_packet_free(upacket);
|
||||
});
|
||||
//NSData *data1 = [NSData dataWithBytesNoCopy:(void*)upacket length:upacket->size freeWhenDone:NO];
|
||||
//[data1 writeToFile:[NSString stringWithFormat:@"/Users/rsms/c-packet-%u.data", tag] atomically:NO];
|
||||
[self sendDispatchData:data callback:callback];
|
||||
}
|
||||
|
||||
|
||||
- (void)sendPacket:(NSDictionary*)packet tag:(uint32_t)tag callback:(void(^)(NSError*))callback {
|
||||
NSError *error = nil;
|
||||
// NSPropertyListBinaryFormat_v1_0
|
||||
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:packet format:NSPropertyListXMLFormat_v1_0 options:0 error:&error];
|
||||
if (!plistData) {
|
||||
callback(error);
|
||||
} else {
|
||||
[self sendPacketOfType:USBMuxPacketTypePlistPayload overProtocol:USBMuxPacketProtocolPlist tag:tag payload:plistData callback:callback];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)sendDispatchData:(dispatch_data_t)data callback:(void(^)(NSError*))callback {
|
||||
off_t offset = 0;
|
||||
dispatch_io_write(channel_, offset, data, queue_, ^(bool done, dispatch_data_t data, int _errno) {
|
||||
//NSLog(@"dispatch_io_write: done=%d data=%p error=%d", done, data, error);
|
||||
if (!done)
|
||||
return;
|
||||
if (callback) {
|
||||
NSError *err = nil;
|
||||
if (_errno) err = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil];
|
||||
callback(err);
|
||||
}
|
||||
});
|
||||
#if PT_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(data); // Release our ref. A ref is still held by dispatch_io_write
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-getter-return-value"
|
||||
|
||||
- (void)sendData:(NSData*)data callback:(void(^)(NSError*))callback {
|
||||
dispatch_data_t ddata = dispatch_data_create((const void*)data.bytes, data.length, queue_, ^{
|
||||
// trick to have the block capture and retain the data
|
||||
[data length];
|
||||
});
|
||||
[self sendDispatchData:ddata callback:callback];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (void)readFromOffset:(off_t)offset length:(size_t)length callback:(void(^)(NSError *error, dispatch_data_t data))callback {
|
||||
dispatch_io_read(channel_, offset, length, queue_, ^(bool done, dispatch_data_t data, int _errno) {
|
||||
if (!done)
|
||||
return;
|
||||
|
||||
NSError *error = nil;
|
||||
if (_errno != 0) {
|
||||
error = [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil];
|
||||
}
|
||||
|
||||
callback(error, data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)cancel {
|
||||
if (channel_) {
|
||||
dispatch_io_close(channel_, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)stop {
|
||||
if (channel_) {
|
||||
dispatch_io_close(channel_, DISPATCH_IO_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
28
Pods/LookinServer/Src/Main/Shared/Peertalk/Peertalk.h
generated
Normal file
28
Pods/LookinServer/Src/Main/Shared/Peertalk/Peertalk.h
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
|
||||
|
||||
//
|
||||
// Peertalk.h
|
||||
// Peertalk
|
||||
//
|
||||
// Created by Marek Cirkos on 12/04/2016.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for Peertalk.
|
||||
FOUNDATION_EXPORT double PeertalkVersionNumber;
|
||||
|
||||
//! Project version string for Peertalk.
|
||||
FOUNDATION_EXPORT const unsigned char PeertalkVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <Peertalk/PublicHeader.h>
|
||||
|
||||
|
||||
#import "Lookin_PTChannel.h"
|
||||
#import "Lookin_PTProtocol.h"
|
||||
#import "Lookin_PTUSBHub.h"
|
||||
|
||||
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|
||||
Reference in New Issue
Block a user