iOS模仿微信长按识别二维码的多种方式
程序员文章站
2023-12-21 12:15:40
参考:https://github.com/nglszs/bcqrcode
方式一:
#import ...
参考:https://github.com/nglszs/bcqrcode
方式一:
#import <uikit/uikit.h> @interface viewcontroller : uiviewcontroller @end ************** #import "viewcontroller.h" @interface viewcontroller () @end @implementation viewcontroller - (void)viewdidload { [super viewdidload]; self.title = @"二维码"; uibarbuttonitem *leftbtn = [[uibarbuttonitem alloc] initwithtitle:@"生成" style:uibarbuttonitemstyleplain target:self action:@selector(backview)]; self.navigationitem.leftbarbuttonitem = leftbtn; uibarbuttonitem *rightbtn = [[uibarbuttonitem alloc] initwithtitle:@"扫描" style:uibarbuttonitemstyleplain target:self action:@selector(scanview)]; self.navigationitem.rightbarbuttonitem = rightbtn; //长按识别图中的二维码,类似于微信里面的功能,前提是当前页面必须有二维码 uilongpressgesturerecognizer *longpress = [[uilongpressgesturerecognizer alloc] initwithtarget:self action:@selector(readcode:)]; [self.view addgesturerecognizer:longpress]; } - (void)readcode:(uilongpressgesturerecognizer *)presssender { if (presssender.state == uigesturerecognizerstatebegan) { //截图 再读取 uigraphicsbeginimagecontextwithoptions(self.view.bounds.size, yes, 0); cgcontextref context = uigraphicsgetcurrentcontext(); [self.view.layer renderincontext:context]; uiimage *image = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); //识别二维码 ciimage *ciimage = [[ciimage alloc] initwithcgimage:image.cgimage options:nil]; cicontext *cicontext = [cicontext contextwithoptions:@{kcicontextusesoftwarerenderer : @(yes)}]; // 软件渲染 cidetector *detector = [cidetector detectoroftype:cidetectortypeqrcode context:cicontext options:@{cidetectoraccuracy : cidetectoraccuracyhigh}];// 二维码识别 nsarray *features = [detector featuresinimage:ciimage]; for (ciqrcodefeature *feature in features) { nslog(@"msg = %@",feature.messagestring); // 打印二维码中的信息 //对结果进行处理 resultviewcontroller *resultvc = [[resultviewcontroller alloc] init]; resultvc.contentstring = feature.messagestring; [self.navigationcontroller pushviewcontroller:resultvc animated:no]; } } } - (void)backview { uiimageview *codeimageview = [[uiimageview alloc] initwithframe:cgrectmake((bcwidth - 200)/2, 100, 200, 200)]; codeimageview.layer.bordercolor = [uicolor orangecolor].cgcolor; codeimageview.layer.borderwidth = 1; [self.view addsubview:codeimageview]; //有图片的时候,也可以不设置圆角 [codeimageview creatcode:@"https://www.baidu.com" image:[uiimage imagenamed:@"bg"] andimagecorner:4]; //没有图片的时候 // [codeimageview creatcode:@"这波可以" image:nil andimagecorner:4]; } - (void)scanview { [self.navigationcontroller pushviewcontroller:[scancodeviewcontroller new] animated:yes]; } - (void)didreceivememorywarning { [super didreceivememorywarning]; // dispose of any resources that can be recreated. } @end ************生成二维码 #import <uikit/uikit.h> @interface uiimageview (creatcode) /** 这里传入二维码的信息,image是加载二维码上方的图片,如果不要图片直接codeimage为nil即可,后面是图片的圆角 */ - (void)creatcode:(nsstring *)codecontent image:(uiimage *)codeimage andimagecorner:(cgfloat)imagecorner; @end ************** #import "uiimageview+creatcode.h" #define imagesize self.bounds.size.width @implementation uiimageview (creatcode) - (void)creatcode:(nsstring *)codecontent image:(uiimage *)codeimage andimagecorner:(cgfloat)imagecorner { //用coreimage框架实现二维码的生成,下面方法最好异步调用 dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{ cifilter *codefilter = [cifilter filterwithname:@"ciqrcodegenerator"]; //每次调用都恢复其默认属性 [codefilter setdefaults]; nsdata *codedata = [codecontent datausingencoding:nsutf8stringencoding]; //设置滤镜数据 [codefilter setvalue:codedata forkey:@"inputmessage"]; //获得滤镜输出的图片 ciimage *outputimage = [codefilter outputimage]; //这里的图像必须经过位图转换,不然会很模糊 uiimage *translateimage = [self creatuiimagefromciimage:outputimage andsize:imagesize]; //这里如果不想设置圆角,直接传一个image就好了 uiimage *resultimage = [self setsuperimage:translateimage andsubimage:[self imagecornerradius:imagecorner andimage:codeimage]]; dispatch_async(dispatch_get_main_queue(), ^{ self.image = resultimage; }); }); } //这里的size我是用imageview的宽度来算的,你可以改为自己想要的size - (uiimage *)creatuiimagefromciimage:(ciimage *)image andsize:(cgfloat)size { //下面是创建bitmao没什么好解释的,不懂得自行百度或者参考官方文档 cgrect extent = cgrectintegral(image.extent); cgfloat scale = min(size/cgrectgetwidth(extent), size/cgrectgetheight(extent)); size_t width = cgrectgetwidth(extent) * scale; size_t height = cgrectgetheight(extent) * scale; cgcolorspaceref colorref = cgcolorspacecreatedevicegray(); cgcontextref contextref = cgbitmapcontextcreate(nil, width, height, 8, 0, colorref, (cgbitmapinfo)kcgimagealphanone); cicontext *context = [cicontext contextwithoptions:nil]; cgimageref imageref = [context createcgimage:image fromrect:extent]; cgcontextsetinterpolationquality(contextref, kcginterpolationnone); cgcontextscalectm(contextref, scale, scale); cgcontextdrawimage(contextref, extent, imageref); cgimageref newimage = cgbitmapcontextcreateimage(contextref); cgcontextrelease(contextref); cgimagerelease(imageref); return [uiimage imagewithcgimage:newimage]; } //这里将二维码上方的图片设置圆角并缩放 - (uiimage *)imagecornerradius:(cgfloat)cornerradius andimage:(uiimage *)image { //这里是将图片进行处理,frame不能太大,否则会挡住二维码 cgrect frame = cgrectmake(0, 0, imagesize/5, imagesize/5); uigraphicsbeginimagecontextwithoptions(frame.size, no, 0); [[uibezierpath bezierpathwithroundedrect:frame cornerradius:cornerradius] addclip]; [image drawinrect:frame]; uiimage *clipimage = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); return clipimage; } - (uiimage *)setsuperimage:(uiimage *)superimage andsubimage:(uiimage *)subimage { //将两张图片绘制在一起 uigraphicsbeginimagecontextwithoptions(superimage.size, yes, 0); [superimage drawinrect:cgrectmake(0, 0, superimage.size.width, superimage.size.height)]; [subimage drawinrect:cgrectmake((imagesize - imagesize/5)/2, (imagesize - imagesize/5)/2, subimage.size.width, subimage.size.height)]; uiimage *resultimage = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); return resultimage; } @end ***************扫描二维码 #import <uikit/uikit.h> #import <avfoundation/avfoundation.h> @interface scancodeviewcontroller : uiviewcontroller<avcapturemetadataoutputobjectsdelegate> { avcapturesession * session; avcapturemetadataoutput * output; nsinteger linenum; bool upordown; nstimer *linetimer; } @property (nonatomic, strong) uiimageview *lineimageview; @property (nonatomic, strong) uiimageview *backimageview; @end ****************** #import "scancodeviewcontroller.h" @implementation scancodeviewcontroller - (void)viewdidload { [super viewdidload]; if ([[[uidevice currentdevice] systemversion] floatvalue] >= 7.0) { avauthorizationstatus authstatus = [avcapturedevice authorizationstatusformediatype:avmediatypevideo]; if (authstatus == avauthorizationstatusdenied || authstatus == avauthorizationstatusrestricted) { [[[uialertview alloc] initwithtitle:nil message:@"本应用无访问相机的权限,如需访问,可在设置中修改" delegate:nil cancelbuttontitle:@"好的" otherbuttontitles:nil, nil] show]; return; } else { //打开相机 avcapturedevice * device = [avcapturedevice defaultdevicewithmediatype:avmediatypevideo]; //创建输入流 avcapturedeviceinput * input = [avcapturedeviceinput deviceinputwithdevice:device error:nil]; //创建输出流 output = [[avcapturemetadataoutput alloc]init]; //设置代理 在主线程里刷新 [output setmetadataobjectsdelegate:self queue:dispatch_get_main_queue()]; //设置扫描区域,这个需要仔细调整 [output setrectofinterest:cgrectmake(64/bcheight, (bcwidth - 320)/2/bcwidth, 320/bcheight, 320/bcwidth)]; //初始化链接对象 session = [[avcapturesession alloc]init]; //高质量采集率 [session setsessionpreset:avcapturesessionpresethigh]; [session addinput:input]; [session addoutput:output]; //设置扫码支持的编码格式 output.metadataobjecttypes=@[avmetadataobjecttypeqrcode,avmetadataobjecttypeean13code, avmetadataobjecttypeean8code, avmetadataobjecttypecode128code]; avcapturevideopreviewlayer * layer = [avcapturevideopreviewlayer layerwithsession:session]; layer.videogravity=avlayervideogravityresizeaspectfill; layer.frame=self.view.layer.bounds; [self.view.layer addsublayer:layer]; } } [self _initview]; } //里面所有的控件可以自己定制,这里只是简单的例子 - (void)_initview { //扫码框 _backimageview = [[uiimageview alloc] initwithframe:cgrectmake(0, 64, bcwidth, bcheight - 64)]; _backimageview.image = [uiimage imagenamed:@"camera_bg"]; [self.view addsubview:_backimageview]; _lineimageview = [[uiimageview alloc] initwithframe:cgrectmake(16, 15, bcwidth - 32, 1)]; _lineimageview.backgroundcolor = [uicolor orangecolor]; [_backimageview addsubview:_lineimageview]; //各种参数设置 linenum = 0; upordown = no; linetimer = [nstimer scheduledtimerwithtimeinterval:0.01 target:self selector:@selector(lineanimation) userinfo:nil repeats:yes]; } -(void)lineanimation { if (upordown == no) { linenum ++; _lineimageview.frame = cgrectmake(cgrectgetminx(_lineimageview.frame), 15 + linenum, bcwidth - 32, 1); cgfloat tempheight = cgrectgetheight(_backimageview.frame) * 321/542; nsinteger height = (nsinteger)tempheight + 20; if (linenum == height) { upordown = yes; } } else { linenum --; _lineimageview.frame = cgrectmake(cgrectgetminx(_lineimageview.frame), 15 + linenum, bcwidth - 32, 1); if (linenum == 0) { upordown = no; } } } #pragma mark avcapturemetadataoutputobjectsdelegate - (void)captureoutput:(avcaptureoutput *)captureoutput didoutputmetadataobjects:(nsarray *)metadataobjects fromconnection:(avcaptureconnection *)connection { if ([metadataobjects count] > 0) { [session stoprunning]; //停止扫码 avmetadatamachinereadablecodeobject *metadataobject = [metadataobjects firstobject]; resultviewcontroller *resultvc = [[resultviewcontroller alloc] init]; resultvc.contentstring = metadataobject.stringvalue; [self.navigationcontroller pushviewcontroller:resultvc animated:no]; } } - (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; [session startrunning]; [linetimer setfiredate:[nsdate distantpast]]; } - (void)viewwilldisappear:(bool)animated { [super viewwilldisappear:animated]; [session stoprunning]; [linetimer setfiredate:[nsdate distantfuture]]; if (![self.navigationcontroller.viewcontrollers containsobject:self]) {//释放timer [linetimer invalidate]; linetimer = nil; } } - (void)dealloc { nslog(@"已释放"); } @end *******吧识别的二维码信息传过来加载网页 #import <uikit/uikit.h> @interface resultviewcontroller : uiviewcontroller @property(nonatomic, retain)nsstring *contentstring; @end ******** #import "resultviewcontroller.h" #import <webkit/webkit.h> @implementation resultviewcontroller - (void)viewdidload { [super viewdidload]; //这个界面我只是简单的处理一下,可以自己定制,实际应用中扫码跳转不可能就这两种逻辑 if ([_contentstring hasprefix:@"http"]) { wkwebview *showview = [[wkwebview alloc] initwithframe:bcscreen]; nsurlrequest *coderequest = [nsurlrequest requestwithurl:[nsurl urlwithstring:_contentstring]]; [showview loadrequest:coderequest]; [self.view addsubview:showview]; } else { uilabel *showlabel = [[uilabel alloc] initwithframe:cgrectmake(0, 80, 200, 50)]; showlabel.center = self.view.center; showlabel.font = [uifont boldsystemfontofsize:16]; showlabel.text = [nsstring stringwithformat:@"扫描结果是---%@",_contentstring]; showlabel.numberoflines = 0; [self.view addsubview:showlabel]; } } @end
方式二:识别网页中的二维码
ios webview中 长按二维码的识别
思路:
长按webview 的过程中 截屏,再去解析是否有二维码,但是有个缺点 就是 万一截了一个 一半的二维码 那就无解了。
在webview中 注入获取点击图片的js 获取图片,再解析。缺点:万一图片过大 需要下载,势必会影响用户体验。
@interface cvwebviewcontroller ()<uigesturerecognizerdelegate> @property (weak, nonatomic) iboutlet uiwebview *webview; @end @implementation cvwebviewcontroller - (void)viewdidload { [self.webview loadrequest:[nsurlrequest requestwithurl:[nsurl urlwithstring:@"http://mp.weixin.qq.com/s?__biz=mzi2odazodazmw==&mid=2650057120&idx=2&sn=c875f7d03ea3823e8dcb3dc4d0cff51d&scene=0#wechat_redirect"]]]; uilongpressgesturerecognizer *longpressed = [[uilongpressgesturerecognizer alloc] initwithtarget:self action:@selector(longpressed:)]; longpressed.delegate = self; [self.webview addgesturerecognizer:longpressed]; } - (void)longpressed:(uitapgesturerecognizer*)recognizer { if (recognizer.state != uigesturerecognizerstatebegan) { return; } cgpoint touchpoint = [recognizer locationinview:self.webview]; nsstring *js = [nsstring stringwithformat:@"document.elementfrompoint(%f, %f).src", touchpoint.x, touchpoint.y]; nsstring *imageurl = [self.webview stringbyevaluatingjavascriptfromstring:js]; if (imageurl.length == 0) { return; } nslog(@"image url:%@",imageurl); nsdata *data = [nsdata datawithcontentsofurl:[nsurl urlwithstring:imageurl]]; uiimage *image = [uiimage imagewithdata:data]; if (image) { //...... //save image or extract qr code } } -(bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldrecognizesimultaneouslywithgesturerecognizer:(uigesturerecognizer *)othergesturerecognizer { return yes; }
以上所述是小编给大家介绍的ios模仿微信长按识别二维码的多种方式,希望对大家有所帮助