iOS 通过局域网(wifi)将图片生成二维码扫码分享

1,618 阅读3分钟

一、需求

       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