欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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模仿微信长按识别二维码的多种方式,希望对大家有所帮助

上一篇:

下一篇: