本地識(shí)別二維碼
文末有 Demo 地址, 挺簡(jiǎn)單的, 不想看字可以直接看 demo
CIDetecor
1, 首先要識(shí)別本地二維碼, webView 基本只是幾條 js 語(yǔ)句的問(wèn)題.
創(chuàng)建 QRCodeDetector 類(lèi):
#import "YNQRCodeDetector.h"
@implementation YNQRCodeDetector
+ (CIQRCodeFeature *)yn_detectQRCodeWithImage:(UIImage *)image {
// 1. 創(chuàng)建上下文
CIContext *context = [[CIContext alloc] init];
// 2. 創(chuàng)建探測(cè)器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
// 3. 識(shí)別圖片獲取圖片特征
CIImage *imageCI = [[CIImage alloc] initWithImage:image];
NSArray<CIFeature *> *features = [detector featuresInImage:imageCI];
CIQRCodeFeature *codeF = (CIQRCodeFeature *)features.firstObject;
return codeF;
}
@end
2, 在本地 imageView 中添加手勢(shì), 處理二維碼識(shí)別的鏈接, 有二維碼顯示保存和識(shí)別, 沒(méi)有只顯示保存
- (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:@"識(shí)別二維碼" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 內(nèi)置瀏覽器打開(kāi)網(wǎng)頁(yè)
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codeF.messageString]];
[self presentViewController:safariVC animated:YES completion:nil];
}]];
}
[self presentViewController:ac animated:YES completion:nil];
}
3, 保存圖片沒(méi)什么好說(shuō)的, 記得 iOS 10 以后手動(dòng)開(kāi)啟相冊(cè)權(quán)限
- (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添加長(zhǎng)按手勢(shì)
因?yàn)轫?xiàng)目需求, 需要改的地方太多了, 我直接寫(xiě)在自定義 WebView 里面了, 直接替換 webView 即可. 因?yàn)楣拘枨蟮?web 沒(méi)有過(guò)于復(fù)雜的功能, 直接寫(xiě)在自定義 webView 就行.
自定義 webView 添加長(zhǎng)按手勢(shì):
- (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;
}
// 獲取點(diǎn)擊區(qū)域坐標(biāo), 通過(guò)坐標(biāo)得到圖片
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];
}
下載圖片
// 因?yàn)樽隽藗€(gè) demo 不想引用三方, 可以用 sdImageDownloader 替代
- (void)imageWithUrl:(NSString *)imageUrl {
// 在子線程中下載圖片, 不在子線程中下載圖片會(huì)造成主線程阻塞, 導(dǎo)致 alertController 需要很久時(shí)間才彈出
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 顯示相關(guān)操作
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:@"識(shí)別二維碼" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codeF.messageString]];
[[self currentViewController] presentViewController:safariVC animated:YES completion:nil];
}]];
}
// 直接用 webView 模態(tài)出控制器
[[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 {
// 屏蔽網(wǎng)頁(yè)自帶操作
[self stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
NSString * jsCallBack = @"window.getSelection().removeAllRanges();";
[webView stringByEvaluatingJavaScriptFromString:jsCallBack];
//js方法遍歷圖片添加點(diǎn)擊事件 返回圖片個(gè)數(shù)
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轉(zhuǎn)換為string
NSString *requestString = [[request URL] absoluteString];
// 判斷創(chuàng)建的字符串內(nèi)容是否以pic:字符開(kāi)始
if ([requestString hasPrefix:@"myweb:imageClick:"]) {
NSString *imageUrl = [requestString substringFromIndex:@"myweb:imageClick:".length];
ENLog(@"------%@", imageUrl);
// 點(diǎn)擊網(wǎng)頁(yè)圖片查看大圖
ShowBigPicController *sb = [[ShowBigPicController alloc] init];
sb.imageURL = imageUrl;
[[self currentViewController] presentViewController:sb animated:NO completion:nil];
return NO;
}
return YES;
}