Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: 无线连接 #164

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions LookinDemo/OC_Pod/LookinDemoOC/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ @implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
#if !TARGET_OS_SIMULATOR
[NSNotificationCenter.defaultCenter postNotificationName:@"Lookin_startWirelessConnection" object:nil];
#endif
return YES;
}

Expand Down
4 changes: 4 additions & 0 deletions LookinDemo/OC_Pod/LookinDemoOC/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSBonjourServices</key>
<array>
<string>_Lookin._tcp</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
Expand Down
23 changes: 21 additions & 2 deletions LookinServer.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ Pod::Spec.new do |spec|
spec.source = { :git => "https://github.com/QMUI/LookinServer.git", :tag => "1.2.8"}
spec.framework = "UIKit"
spec.requires_arc = true

spec.subspec 'Core' do |ss|
ss.source_files = ['Src/Main/**/*', 'Src/Base/**/*']
ss.exclude_files = 'Src/Main/Shared/Channel/**/*'
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER=1',
'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER'
Expand All @@ -37,7 +38,7 @@ Pod::Spec.new do |spec|
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_DISABLE_HOOK=1',
}
end

# CocoaPods 不支持多个 subspecs 和 configurations 并列
# "pod 'LookinServer', :subspecs => ['Swift', 'NoHook'], :configurations => ['Debug']" is not supported by CocoaPods
# https://github.com/QMUI/LookinServer/issues/134
Expand All @@ -50,4 +51,22 @@ Pod::Spec.new do |spec|
}
end

spec.subspec 'SwiftAndWireless' do |ss|
ss.dependency 'LookinShared/Wireless'
ss.dependency 'LookinServer/Core'
ss.source_files = 'Src/Swift/**/*'
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED=1 LOOKIN_SERVER_DISABLE_HOOK=1 LOOKIN_SERVER_WIRELESS=1',
'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) LOOKIN_SERVER_SWIFT_ENABLED',
}
end

spec.subspec 'Wireless' do |ss|
ss.dependency 'LookinServer/Core'
ss.dependency 'LookinShared/Wireless'
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) LOOKIN_SERVER_WIRELESS=1'
}
end

end
11 changes: 11 additions & 0 deletions LookinShared.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@ Pod::Spec.new do |spec|
'Src/Main/Shared/**/*',
'Src/Base/**/*'
]
spec.exclude_files = 'Src/Main/Shared/Channel/**/*'
spec.default_subspec = :none

spec.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER=1'
}

spec.subspec 'Wireless' do |ss|
ss.source_files = 'Src/Main/Shared/Channel/**/*'
ss.dependency 'CocoaAsyncSocket'
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SHOULD_COMPILE_LOOKIN_SERVER=1 LOOKIN_SERVER_WIRELESS=1'
}
end
end
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ To use Lookin macOS app, you need to integrate LookinServer (iOS Framework of Lo
`pod 'LookinServer', :subspecs => ['Swift'], :configurations => ['Debug']`
### Objective-C Project
`pod 'LookinServer', :configurations => ['Debug']`

### [Optianal] Wireless Connection
`pod 'LookinServer/Wireless', :configurations => ['Debug']`

And you need to add follow content to Info.plist. The name of `NSBonjourServices` **MUST** be `_Lookin._tcp`.

```plist
<key>NSLocalNetworkUsageDescription</key>
<string>Local Network Usage Description</string>
<key>NSBonjourServices</key>
<array>
<string>_Lookin._tcp</string>
</array>
```
Also, the wireless ability does not start automatically, you need to send a notification to turn it on. And you can also send a notification to turn it off. <br>
Notification Names: `Lookin_startWirelessConnection` and `Lookin_endWirelessConnection`

## via Swift Package Manager:
`https://github.com/QMUI/LookinServer/`

Expand Down Expand Up @@ -44,7 +61,7 @@ Lookin 可以查看与修改 iOS App 里的 UI 对象,类似于 Xcode 自带
如果这是你的 iOS 项目第一次使用 Lookin,则需要先把 LookinServer 这款 iOS Framework 集成到你的 iOS 项目中。

> **Warning**
>
>
> 1. 不要在 AppStore 模式下集成 LookinServer。
> 2. 不要使用早于 1.0.6 的版本,因为它包含一个严重 Bug,可能导致线上事故: https://qxh1ndiez2w.feishu.cn/wiki/Z9SpwT7zWiqvYvkBe7Lc6Disnab
## 通过 CocoaPods:
Expand All @@ -53,6 +70,21 @@ Lookin 可以查看与修改 iOS App 里的 UI 对象,类似于 Xcode 自带
`pod 'LookinServer', :subspecs => ['Swift'], :configurations => ['Debug']`
### Objective-C 项目
`pod 'LookinServer', :configurations => ['Debug']`
### [可选] 无线连接功能
`pod 'LookinServer/Wireless', :configurations => ['Debug']`

你需要将下面的内容添加进你的`Info.plist`。 `NSBonjourServices`的值**必须是**`_Lookin._tcp`。

```plist
<key>NSLocalNetworkUsageDescription</key>
<string>Local Network Usage Description</string>
<key>NSBonjourServices</key>
<array>
<string>_Lookin._tcp</string>
</array>
```
并且,无线功能不会自动启动,需要你发送通知来开启该功能,也支持发送通知来关闭它。<br>
通知名称`Lookin_startWirelessConnection`和`Lookin_endWirelessConnection`

## 通过 Swift Package Manager:
`https://github.com/QMUI/LookinServer/`
Expand Down
16 changes: 14 additions & 2 deletions Src/Main/Server/Connection/LKS_ConnectionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,21 @@ extern NSString *const LKS_ConnectionDidEndNotificationName;

@property(nonatomic, assign) BOOL applicationIsActive;

- (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag;
#if LOOKIN_SERVER_WIRELESS
- (void)startWirelessConnection;

- (void)pushData:(NSObject *)data type:(uint32_t)type;
- (void)endWirelessConnection;
#endif

- (BOOL)isConnected;

#if LOOKIN_SERVER_WIRELESS
- (BOOL)isWirelessConnnect;
#endif

- (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag isWireless:(BOOL)isWireless;

- (void)pushData:(NSObject *)data type:(uint32_t)type isWireless:(BOOL)isWireless;

@end

Expand Down
149 changes: 136 additions & 13 deletions Src/Main/Server/Connection/LKS_ConnectionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#import "LookinServerDefines.h"
#import "LKS_TraceManager.h"
#import "LKS_MultiplatformAdapter.h"
#import "ECOChannelManager.h"

#if LOOKIN_SERVER_WIRELESS
@import CocoaAsyncSocket;
#endif

NSString *const LKS_ConnectionDidEndNotificationName = @"LKS_ConnectionDidEndNotificationName";

Expand All @@ -24,6 +29,12 @@ @interface LKS_ConnectionManager () <Lookin_PTChannelDelegate>
@property(nonatomic, weak) Lookin_PTChannel *peerChannel_;

@property(nonatomic, strong) LKS_RequestHandler *requestHandler;
@property(nonatomic, strong) LKS_RequestHandler *wirelessRequestHandler;

@property(nonatomic, strong) ECOChannelManager *wirelessChannel;
@property(nonatomic, strong) ECOChannelDeviceInfo *wirelessDevice;

@property BOOL hasStartWirelessConnnection;

@end

Expand Down Expand Up @@ -52,6 +63,13 @@ - (instancetype)init {

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspect:) name:@"Lookin_2D" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspect:) name:@"Lookin_3D" object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspectIn2D:) name:@"Lookin_2D" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspectIn3D:) name:@"Lookin_3D" object:nil];
#if LOOKIN_SERVER_WIRELESS
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startWirelessConnection) name:@"Lookin_startWirelessConnection" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endWirelessConnection) name:@"Lookin_endWirelessConnection" object:nil];
#endif
[[NSNotificationCenter defaultCenter] addObserverForName:@"Lookin_Export" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[[LKS_ExportManager sharedInstance] exportAndShare];
}];
Expand All @@ -61,10 +79,95 @@ - (instancetype)init {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleGetLookinInfo:) name:@"GetLookinInfo" object:nil];

self.requestHandler = [LKS_RequestHandler new];
self.wirelessRequestHandler = LKS_RequestHandler.wireless;
}
return self;
}

#if LOOKIN_SERVER_WIRELESS
- (void)startWirelessConnection {
#if TARGET_OS_SIMULATOR
NSLog(@"LookinServer - warning: you should not start Wireless Connection on Simulator. We wouldn't start it.");
return;
#endif
self.hasStartWirelessConnnection = YES;
if (!self.wirelessChannel) {
#if TARGET_OS_IPHONE
self.wirelessChannel = ECOChannelManager.new;
__weak __typeof(self) weakSelf = self;
// 接收到数据回调
self.wirelessChannel.receivedBlock = ^(ECOChannelDeviceInfo *device, NSData *data, NSDictionary *extraInfo) {
NSLog(@"🚀 Lookin receivedBlock device:%@", device);
NSNumber *type = extraInfo[@"type"];
NSNumber *tag = extraInfo[@"tag"];
id object = nil;
id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if ([unarchivedObject isKindOfClass:[LookinConnectionAttachment class]]) {
LookinConnectionAttachment *attachment = (LookinConnectionAttachment *)unarchivedObject;
object = attachment.data;
} else {
object = unarchivedObject;
}
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.wirelessRequestHandler handleRequestType:type.intValue tag:tag.intValue object:object];
});
};
// 设备连接变更
self.wirelessChannel.deviceBlock = ^(ECOChannelDeviceInfo *device, BOOL isConnected) {
NSLog(@"🚀 Lookin deviceBlock device:%@", device);
if ([device isEqual:weakSelf.wirelessDevice] && !isConnected) {
weakSelf.wirelessDevice = nil;
}
};
// 授权状态变更回调
self.wirelessChannel.authStateChangedBlock = ^(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) {
NSLog(@"🚀 Lookin authStateChangedBlock device:%@ authState:%ld", device, authState);
if (authState == ECOAuthorizeResponseType_AllowAlways) {
weakSelf.wirelessDevice = device;
}
};
// 请求授权状态认证回调
self.wirelessChannel.requestAuthBlock = ^(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) {
NSLog(@"🚀 Lookin requestAuthBlock device:%@ authState:%ld", device, authState);
NSString *title = @"Lookin 连接请求";
NSString *message = [NSString stringWithFormat:@"%@ 的Lookin想要连接你的设备,如果你想启用调试功能,请选择允许", device.hostName ?: device.ipAddress];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *denyAction = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[weakSelf.wirelessChannel sendAuthorizationMessageToDevice:device state:ECOAuthorizeResponseType_Deny showAuthAlert:NO];
}];
UIAlertAction *allowOnceAction = [UIAlertAction actionWithTitle:@"允许一次" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf.wirelessChannel sendAuthorizationMessageToDevice:device state:ECOAuthorizeResponseType_AllowOnce showAuthAlert:NO];
weakSelf.wirelessDevice = device;
}];
UIAlertAction *allowAlwaysAction = [UIAlertAction actionWithTitle:@"始终允许" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf.wirelessChannel sendAuthorizationMessageToDevice:device state:ECOAuthorizeResponseType_AllowAlways showAuthAlert:NO];
weakSelf.wirelessDevice = device;
}];
[alertController addAction:denyAction];
[alertController addAction:allowOnceAction];
[alertController addAction:allowAlwaysAction];

dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootVC presentViewController:alertController animated:YES completion:nil];
});
};
#endif
}
}

- (void)endWirelessConnection {
self.hasStartWirelessConnnection = NO;
GCDAsyncSocket *asyncSocket = [self.wirelessChannel valueForKeyPath:@"socketChannel.cSocket"];
if (asyncSocket) {
[asyncSocket setDelegate:nil];
[asyncSocket disconnect];
[self.wirelessChannel setValue:nil forKeyPath:@"socketChannel.cSocket"];
}
self.wirelessChannel = nil;
}
#endif

- (void)_handleWillResignActiveNotification {
self.applicationIsActive = NO;

Expand Down Expand Up @@ -153,23 +256,43 @@ - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag {
[self _sendData:data frameOfType:requestType tag:tag];
- (BOOL)isConnected {
#if LOOKIN_SERVER_WIRELESS
return self.isWirelessConnnect || (self.peerChannel_ && self.peerChannel_.isConnected);
#else
return self.peerChannel_ && self.peerChannel_.isConnected;
#endif
}

- (void)pushData:(NSObject *)data type:(uint32_t)type {
[self _sendData:data frameOfType:type tag:0];
#if LOOKIN_SERVER_WIRELESS
- (BOOL)isWirelessConnnect {
return self.wirelessChannel.isConnected;
}
#endif

- (void)_sendData:(NSObject *)data frameOfType:(uint32_t)frameOfType tag:(uint32_t)tag {
if (self.peerChannel_) {
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:data];
dispatch_data_t payload = [archivedData createReferencingDispatchData];

[self.peerChannel_ sendFrameOfType:frameOfType tag:tag withPayload:payload callback:^(NSError *error) {
if (error) {
}
}];
- (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag isWireless:(BOOL)isWireless {
[self _sendData:data frameOfType:requestType tag:tag isWireless:isWireless];
}

- (void)pushData:(NSObject *)data type:(uint32_t)type isWireless:(BOOL)isWireless {
[self _sendData:data frameOfType:type tag:0 isWireless:isWireless];
}

- (void)_sendData:(NSObject *)data frameOfType:(uint32_t)frameOfType tag:(uint32_t)tag isWireless:(BOOL)isWireless {
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:data];
if (isWireless) {
if (self.wirelessDevice.isConnected) {
[self.wirelessChannel sendPacket:archivedData extraInfo:@{@"tag": @(tag), @"type": @(frameOfType)} toDevice:self.wirelessDevice];
}
} else {
if (self.peerChannel_) {
dispatch_data_t payload = [archivedData createReferencingDispatchData];

[self.peerChannel_ sendFrameOfType:frameOfType tag:tag withPayload:payload callback:^(NSError *error) {
if (error) {
}
}];
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions Src/Main/Server/Connection/LKS_RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

@interface LKS_RequestHandler : NSObject

+ (instancetype)wireless;

- (BOOL)canHandleRequestType:(uint32_t)requestType;

- (void)handleRequestType:(uint32_t)requestType tag:(uint32_t)tag object:(id)object;
Expand Down
Loading