本地识别二维码
文末有 Demo 地址, 挺简单的, 不想看字可以直接看 demo
CIDetecor
1, 首先要识别本地二维码, webView 基本只是几条 js 语句的问题.
创建 QRCodeDetector 类:
#import "YNQRCodeDetector.h"
@implementation YNQRCodeDetector
+ (CIQRCodeFeature *)yn_detectQRCodeWithImage:(UIImage *)image {
// 1. 创建上下文
CIContext *context = [[CIContext alloc] init];
// 2. 创建探测器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
// 3. 识别图片获取图片特征
CIImage *imageCI = [[CIImage alloc] initWithImage:image];
NSArray<CIFeature *> *features = [detector featuresInImage:imageCI];
CIQRCodeFeature *codeF = (CIQRCodeFeature *)features.firstObject;
return codeF;
}
@end
2, 在本地 imageView 中添加手势, 处理二维码识别的链接, 有二维码显示保存和识别, 没有只显示保存
- (void)imageLongPress {
UIAlertController *ac = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
CIQRCodeFeature *codeF = [YNQRCodeDetector yn_detectQRCodeWithImage:self.imageView.image];
[ac addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}]];
[ac addAction:[UIAlertAction actionWithTitle:@"保存图片" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self savePicture];
}]];
if (codeF.messageString) {
[ac addAction:[UIAlertAction actionWithTitle:@"识别二维码" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 内置浏览器打开网页
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codeF.messageString]];
[self presentViewController:safariVC animated:YES completion:nil];
}]];
}
[self presentViewController:ac animated:YES completion:nil];
}
3, 保存图片没什么好说的, 记得 iOS 10 以后手动开启相册权限
- (void)savePicture {
if (self.imageView.image == nil) {
// [SVProgressHUD showErrorWithStatus:@"图片还未加载"];
} else {
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
- (void)image:(UIImage *)image
didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo {
if (error) {
// [SVProgressHUD showErrorWithStatus:@"保存失败"];
} else {
// [SVProgressHUD showSuccessWithStatus:@"保存成功"];
}
}
WebView上的一些处理
WebView添加长按手势
因为项目需求, 需要改的地方太多了, 我直接写在自定义 WebView 里面了, 直接替换 webView 即可. 因为公司需求的 web 没有过于复杂的功能, 直接写在自定义 webView 就行.
自定义 webView 添加长按手势:
- (instancetype)init {
self = [super init];
if (self) {
[self basicConfigure];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self basicConfigure];
}
return self;
}
- (void)basicConfigure {
self.delegate = self;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressWebPic:)];
longPress.delegate = self;
[self addGestureRecognizer:longPress];
}
- (void)longPressWebPic:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state != UIGestureRecognizerStateBegan) {
return;
}
// 获取点击区域坐标, 通过坐标得到图片
CGPoint touchPoint = [recognizer locationInView:self];
NSString *imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", touchPoint.x, touchPoint.y];
NSString *urlToSave = [self stringByEvaluatingJavaScriptFromString:imgURL];
if (urlToSave.length == 0) {
return;
}
// ENLog(@"%@", urlToSave);
[self imageWithUrl:urlToSave];
}
下载图片
// 因为做了个 demo 不想引用三方, 可以用 sdImageDownloader 替代
- (void)imageWithUrl:(NSString *)imageUrl {
// 在子线程中下载图片, 不在子线程中下载图片会造成主线程阻塞, 导致 alertController 需要很久时间才弹出
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:imageUrl];
NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue new]];
NSURLRequest *imgRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:imgRequest completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
return ;
}
NSData *imageData = [NSData dataWithContentsOfURL:location];
// 在主线程中配置 UI 显示相关操作
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
UIAlertController *ac = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
CIQRCodeFeature *codeF = [YNQRCodeDetector yn_detectQRCodeWithImage:image];
[ac addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}]];
[ac addAction:[UIAlertAction actionWithTitle:@"保存图片" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self savePicture:image];
}]];
if (codeF.messageString) {
[ac addAction:[UIAlertAction actionWithTitle:@"识别二维码" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codeF.messageString]];
[[self currentViewController] presentViewController:safariVC animated:YES completion:nil];
}]];
}
// 直接用 webView 模态出控制器
[[self currentViewController] presentViewController:ac animated:YES completion:nil];
});
}];
[task resume];
});
}
获取最上层控制器
- (UIViewController *)currentViewController {
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
UIViewController *vc = keyWindow.rootViewController;
while (vc.presentedViewController) {
vc = vc.presentedViewController;
if ([vc isKindOfClass:[UINavigationController class]]) {
vc = [(UINavigationController *)vc visibleViewController];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
vc = [(UITabBarController *)vc selectedViewController];
}
}
return vc;
}
- (UINavigationController *)currentNavigationController {
return [self currentViewController].navigationController;
}
处理 WebView 代理方法 (js 处理)
- (void)webViewDidFinishLoad:(UIWebView *)webView {
// 屏蔽网页自带操作
[self stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
NSString * jsCallBack = @"window.getSelection().removeAllRanges();";
[webView stringByEvaluatingJavaScriptFromString:jsCallBack];
//js方法遍历图片添加点击事件 返回图片个数
static NSString * const jsGetImages =
@"function getImages(){\
var objs = document.getElementsByTagName(\"img\");\
for(var i=0;i<objs.length;i++){\
objs[i].onclick=function(){\
document.location=\"myweb:imageClick:\"+this.src;\
};\
};\
return objs.length;\
};";
// 获取图片链接
[webView stringByEvaluatingJavaScriptFromString:jsGetImages];//注入js方法
[webView stringByEvaluatingJavaScriptFromString:@"getImages()"];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
// 将url转换为string
NSString *requestString = [[request URL] absoluteString];
// 判断创建的字符串内容是否以pic:字符开始
if ([requestString hasPrefix:@"myweb:imageClick:"]) {
NSString *imageUrl = [requestString substringFromIndex:@"myweb:imageClick:".length];
ENLog(@"------%@", imageUrl);
// 点击网页图片查看大图
ShowBigPicController *sb = [[ShowBigPicController alloc] init];
sb.imageURL = imageUrl;
[[self currentViewController] presentViewController:sb animated:NO completion:nil];
return NO;
}
return YES;
}