一、需求
App内生成的图片,以二维码的形式分享给其他用户(没有后端)
二、思路
App内部开启本地服务器,通过局域网传输文件,首选第三方开源框架GCDWebServer在Podfile添加
pod "GCDWebServer"
通过GCDWebServer 开启本地服务器,然后将图片添加到html,域名为链接,在用域名生成一个二维码
效果如图:(需要在同一局域网)
浏览器打开:
三、操作步骤
1.首先在项目中的podfile添加GCDWebServer
2.在项目中需要用到这个功能的页面或者在AppDelegate页面中(非必要性,不建议在AppDelegate创建),导入头文件,遵循协议:
#import <GCDWebServer.h>
#import <GCDWebServerDataResponse.h>
@interface YMGenerateQrcodeController () <GCDWebServerDelegate>
{
GCDWebServer *_webServer;
}
@end
@implementation YMGenerateQrcodeController
- (void)viewDidLoad {
[super viewDidLoad];
[self startLocalServer];
}
- (void)startLocalServer{
// 创建 server
_webServer = [[GCDWebServer alloc] init];
_webServer.delegate = self;
UIImage *image = [UIImage imageNamed:@"test"];
NSString *base64 = [self imageToString:image];
NSString *htmlPath = [NSString stringWithFormat:@"<html><body><img src='data:image/png;base64,%@'/></body></html>",base64];
// 添加 handler
[_webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
return [GCDWebServerDataResponse responseWithHTML:htmlPath];
}];
// 服务器端口 8080
[_webServer startWithPort:8080 bonjourName:nil];
}
//将图片转化为base64
- (NSString *)imageToString:(UIImage *)image {
NSData *imagedata = UIImagePNGRepresentation(image);
NSString *image64 = [imagedata base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return image64;
}
- (void)webServerDidStart:(GCDWebServer *)server{
YMLog(@"本地服务启动成功");
YMLog(@"访问域名,浏览器打开: %@ ", server.serverURL);
[self creatQrcode:server.serverURL];//服务器开启成功,域名生成二维码
}
3.这里遇到一个坑,如果用图片用本地路径,html加载不出来,网上有一个方法,用于UIWebView可行,但是在WKWebView还是加载不出来,代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 375, 667)];
[self.view addSubview:self.webView];
[NSURLProtocol registerClass:[MyCustomURLProtocol class]];
NSString *localHtmlFilePath = [[NSBundle mainBundle] pathForResource:@"file" ofType:@"html"];
NSString *localHtmlFileURL = [NSString stringWithFormat:@"file://%@", localHtmlFilePath];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:localHtmlFileURL]]];
NSString *html = [NSString stringWithContentsOfFile:localHtmlFilePath encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:html baseURL:nil];
}
新建类,NSURLProtocol 重写load方法:
#import <Foundation/Foundation.h>
@interface MyCustomURLProtocol : NSURLProtocol
{
NSURLRequest *request;
}
+ (BOOL)canInitWithRequest:(NSURLRequest *)theRequest;
@end
#import "MyCustomProtocol.h"
@implementation MyCustomURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest *)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
NSLog(@"start loading !");
}
- (void)stopLoading
{
NSLog(@"something went wrong!");
}
@end
这个方法可以借鉴测试使用,现在苹果已经禁止UIWebView,所以没多大必要研究下去。
4.图片加载不出来,比较有效而且直接的方法就是将图片转为base64
UIImage *image = [UIImage imageNamed:@"test"];
NSString *base64 = [self imageToString:image];
NSString *htmlPath = [NSString stringWithFormat:@"<html><body><img src='data:image/png;base64,%@'/></body></html>",base64];
//将图片转化为base64
- (NSString *)imageToString:(UIImage *)image {
NSData *imagedata = UIImagePNGRepresentation(image);
NSString *image64 = [imagedata base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return image64;
}
5.如果在某个页面开启服务器,但是当退出这个页面的时候,服务器就会被关闭,如果要服务器开启了就一直开启,直到退出App,可以用单例保存着webServer,如下
- (void)startLocalServer{
//判断单例是否保存着服务器,如果是则先关闭,这里设置为nil无效的
if ([AppSingleInstance sharedInstance].webServer) {
[[AppSingleInstance sharedInstance].webServer stop];
}
// Create server
_webServer = [[GCDWebServer alloc] init];
_webServer.delegate = self;
[AppSingleInstance sharedInstance].webServer = _webServer;
UIImage *image = [UIImage imageNamed:@"test"];
NSString *base64 = [self imageToString:image];
NSString *htmlPath = [NSString stringWithFormat:@"<html><body><img src='data:image/png;base64,%@'/></body></html>",base64];
// Add a handler to respond to GET requests on any URL
[_webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
return [GCDWebServerDataResponse responseWithHTML:htmlPath];
}];
// Start server on port 8080
[_webServer startWithPort:8080 bonjourName:nil];
}
四、以URL生成二维码
接到这个需求的时候,本想直接用图片生成一个二维码,简单完成任务,奈何这是不可行的,还是老老实实码代码
- (void)creatQrcode:(NSURL *)URL
{
//1、创建滤镜对象
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
//2、恢复默认设置
[filter setDefaults];
//3、设置数据
// NSString *info = @"https://apps.apple.com/cn/app/youboard/id1550577086?uo=4";
NSString *info = URL.absoluteString;
NSData *infoData = [info dataUsingEncoding:NSUTF8StringEncoding];
[filter setValue:infoData forKey:@"inputMessage"];
//4、生成二维码
CIImage *outputImage = [filter outputImage];
self.image.image = [outputImage ym_createNonInterpolatedWithSize:150];
}
新建CIImage的扩展,进行简单的图片设置大小
#import <CoreImage/CoreImage.h>
#import <UIKit/UIKit.h>
@interface CIImage (Extension)
- (UIImage *)ym_createNonInterpolatedWithSize:(CGFloat)size;
@end
#import "CIImage+Extension.h"
@implementation CIImage (Extension)
/**
根据CIImage生成指定大小的UIImage
@param size 图片宽高
@return CIImage
*/
- (UIImage *)ym_createNonInterpolatedWithSize:(CGFloat)size
{
CGRect extent = CGRectIntegral(self.extent);
CGFloat scale = MIN(size / CGRectGetWidth(extent), size / CGRectGetHeight(extent));
//1.创建bitmap
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef bitmapImage = [context createCGImage:self fromRect:extent];
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
//2.保存bitmap到图片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
return [UIImage imageWithCGImage:scaledImage];
}
@end