目标
- App内启停HTTP服务。
- 供其它设备访问。
- 可以下载指定资源。
主要内容
- CocoaHTTPServer 框架使用
- iOS 拍照、存储、读取
- 搭建简单的HTML界面
具体步骤
添加 CocoaHTTPServer 框架
下载 CocoaHTTPServer 框架,将 HTTP、GCDAsyncSocket、Response、Categories 的相关内容引入到项目。
初始化并启动服务
- 创建服务首页: /web/index.html
/* index.html */
CocoaHTTPServer
Welcome to CocoaHTTPServer
- 初始化服务及启停
- (void)initHTTPServer
{
self.httpServer = [[HTTPServer alloc] init];
[self.httpServer setType:@"_http._tcp."];
[self setHttpServerDocumentRoot];
}
- (void)startupServer
{
NSError *error;
[self.httpServer start:&error];
if (error)
{
NSLog(@"%@", error);
}
else
{
self.port = [self.httpServer listeningPort];
NSLog(@"Server started port:%d", self.port);
}
}
- (void)stopServer
{
[self.httpServer stop:YES];
}
此时访问手机IP及服务监听端口组成的地址:xxx.xxx.xx.xx: port,即可看到 Welcome to CocoaHTTPServer。
拍照存储
- 相机初始化及运行
- (void)initAVCaptureSession
{
// 创建session
self.captureSession = [[AVCaptureSession alloc] init];
// 初始化设备
NSError *error;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 初始化输入
self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
if (error)
{
NSLog(@"%@", error);
}
// 初始化输出
self.stillImgOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
[self.stillImgOutput setOutputSettings:outputSettings];
// 配置session
if ([self.captureSession canAddInput:self.videoInput])
{
[self.captureSession addInput:self.videoInput];
}
if ([self.captureSession canAddOutput:self.stillImgOutput])
{
[self.captureSession addOutput:self.stillImgOutput];
}
// previewLayer
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
self.previewLayer.frame = CGRectMake(0, 0, MAINSCREEN_WIDTH, MAINSCREEN_HEIGHT);
[self.view.layer addSublayer:self.previewLayer];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.captureSession startRunning]; // startRunning
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.captureSession stopRunning]; // stopRunning
}
- 拍照存储与记录
- (void)tapBtnClicked:(UIButton *)tapBtn
{
AVCaptureConnection *stillImageConnection = [self.stillImgOutput connectionWithMediaType:AVMediaTypeVideo];
UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
AVCaptureVideoOrientation avcaptureOrientation = [self avOrientationForDeviceOrientation:curDeviceOrientation];
[stillImageConnection setVideoOrientation:avcaptureOrientation];
[stillImageConnection setVideoScaleAndCropFactor:1];
__weak typeof(self) weakself = self;
[self.stillImgOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
[weakself.captureSession stopRunning];
// 存储进Caches
[weakself saveImageData:imageData];
}];
}
- (void)saveImageData:(NSData *)imageData
{
BOOL isDirectory = NO;
if (![[NSFileManager defaultManager] fileExistsAtPath:ImageDirPath isDirectory:&isDirectory])
{
NSError *error;
[[NSFileManager defaultManager] createDirectoryAtPath:ImageDirPath withIntermediateDirectories:YES attributes:nil error:&error];
}
NSString *imagePath = [ImageDirPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", [self getTimeString]]];
[imageData writeToFile:imagePath atomically:YES];
// 记录进 plist
[self saveImageDetailToPlist:imagePath];
}
- (void)saveImageDetailToPlist:(NSString *)imagePath
{
NSString *filename = [[imagePath componentsSeparatedByString:@"/"] lastObject];
NSMutableArray *imgDetailAry = [NSMutableArray arrayWithContentsOfFile:ImagesPlistPath];
if (!imgDetailAry)
{
NSMutableDictionary *imgDetailDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:filename, @"filename", imagePath, @"imagePath", nil];
imgDetailAry = [NSMutableArray arrayWithObject:imgDetailDict];
[imgDetailAry writeToFile:ImagesPlistPath atomically:YES];
}
else
{
NSMutableDictionary *imgDetailDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:filename, @"filename", imagePath, @"imagePath", nil];
[imgDetailAry addObject:imgDetailDict];
[imgDetailAry writeToFile:ImagesPlistPath atomically:YES];
}
ShowMBProgressHUDText(@"照片已存储")
[self.captureSession startRunning];
}
动态搭建服务首页
- 根据照片信息决定 index 内容
- (void)initIndexHtmlDynamicContents
{
NSString *indexPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"web/index.html"];
NSMutableArray *imgDetailAry = [NSMutableArray arrayWithContentsOfFile:ImagesPlistPath];
NSString *htmlStr;
if (!imgDetailAry)
{
htmlStr = @"CocoaHTTPServer 暂无照片
";
}
else
{
NSString *ulString = [NSString string];
for (int i = 0; i < imgDetailAry.count; i++)
{
NSDictionary *imgDict = imgDetailAry[i];
ulString = [ulString stringByAppendingString:[NSString stringWithFormat:@"%@-- download", imgDict[@"filename"], [self getIPAddress], self.port, i]];
}
htmlStr = [NSString stringWithFormat:@"CocoaHTTPServer The Pictures
%@
", ulString];
}
NSError *writeToFileError;
[htmlStr writeToFile:indexPath atomically:YES encoding:NSUTF8StringEncoding error:&writeToFileError];
}
实现下载
- 给 index.html 添加下载按钮
// 动态更新 index.html
- (void)updateIndexHtmlDynamicContents:(NSMutableArray *)imgDetailAry
{
NSString *htmlStr;
NSString *ulString;
NSString *indexPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"web/index.html"];
for (int i = 0; i < imgDetailAry.count; i++)
{
NSDictionary *imgDict = imgDetailAry[i];
ulString = [ulString stringByAppendingString:[NSString stringWithFormat:@"%@-- download", imgDict[@"filename"], [self getIPAddress], self.port, i]];
}
htmlStr = [NSString stringWithFormat:@"CocoaHTTPServer The Pictures
%@
", ulString];
NSError *writeToFileError;
[htmlStr writeToFile:indexPath atomically:YES encoding:NSUTF8StringEncoding error:&writeToFileError];
}
- 创建 MyHTTPConnection 类
实现如下代理方法:
/* 返回要下载的文件 */
- (NSObject *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
if (path.length == 1)
{
return [super httpResponseForMethod:method URI:path];
}
NSMutableArray *imgDetailAry = [NSMutableArray arrayWithContentsOfFile:ImagesPlistPath];
NSDictionary *imgDetailDict = imgDetailAry[path.integerValue];
DITHTTPFileResponse *fileResponse = [[DITHTTPFileResponse alloc] initWithFilePath:imgDetailDict[@"imagePath"] forConnection:self];
fileResponse.filename = imgDetailDict[@"filename"];
return fileResponse;
}
- 给 Server 配置 MyHTTPConnection
/* 初始化 server 时配置 */
[self.httpServer setConnectionClass:[MyHTTPConnection class]];
- 创建 MyHTTPFileResponse 类
实现如下代理方法:
/* 告诉浏览器这是下载以及下载的文件名称 */
- (NSDictionary *)httpHeaders
{
NSMutableDictionary *headersDict = [NSMutableDictionary dictionary];
[headersDict setValue:@"application/octet-stream" forKey:@"Content-Type"];
[headersDict setValue:[NSString stringWithFormat:@"attachment; filename=%@", self.filename] forKey:@"Content-Disposition"];
return headersDict;
}
总结
- 其它设备向App内服务上传资源同样可以实现,缓缓再写。
- Github: DiTing
-
截图如下: