序言
前面我們已經(jīng)調(diào)到過怎么制作二維碼,在我們能夠生成二維碼之后溜畅,如何對二維碼進行掃描呢憋活?
在iOS7之前铝耻,大部分應用中使用的二維碼掃描是第三方的掃描框架,例如ZXing或者ZBar贞远。使用時集成麻煩畴博,出錯也不方便調(diào)試。在iOS7之后蓝仲,蘋果自身提供了二維碼的掃描功能俱病,從效率上來說,原生的二維碼遠高于這些第三方框架袱结。本文講解如何使用原生框架實現(xiàn)二維碼掃描功能亮隙,并且進行掃描后的項目跳轉(zhuǎn)。
ps:本期的源代碼會在文章結尾給出鏈接
掃描相關類
二維碼掃描需要獲取攝像頭并讀取照片信息垢夹,因此我們需要導入系統(tǒng)的AVFoundation框架溢吻,創(chuàng)建視頻會話。我們需要用到一下幾個類:
- AVCaptureSession 會話對象棚饵。此類作為硬件設備輸入輸出信息的橋梁煤裙,承擔實時獲取設備數(shù)據(jù)的責任
- AVCaptureDeviceInput 設備輸入類。這個類用來表示輸入數(shù)據(jù)的硬件設備噪漾,配置抽象設備的port
- AVCaptureMetadataOutput 輸出類硼砰。這個支持二維碼、條形碼等圖像數(shù)據(jù)的識別
-
AVCaptureVideoPreviewLayer 圖層類欣硼。用來快速呈現(xiàn)攝像頭獲取的原始數(shù)據(jù)
二維碼掃描功能的實現(xiàn)步驟是創(chuàng)建好會話對象题翰,用來獲取從硬件設備輸入的數(shù)據(jù),并實時顯示在界面上诈胜。在掃描到相應圖像數(shù)據(jù)的時候豹障,通過AVCaptureVideoPreviewLayer類型進行返回
應用跳轉(zhuǎn)
在使用第三方登陸焦匈、分享sdk的時候,我們的項目會在本機安裝有目標平臺的應用的情況下進行應用跳轉(zhuǎn)缓熟,并且傳遞信息過去摔笤。這在沙盒機制下的iOS應用而言,理應是不符合規(guī)則的垦写。但是吕世,iOS SDK給我們提供了一個叫做url scheme的機制來實現(xiàn)這個功能梯投。
url scheme讓我們可以像使用Safari打開網(wǎng)頁的方式跳轉(zhuǎn)到其他應用中,并使用類似網(wǎng)絡請求的GET請求的參數(shù)拼湊方式來在不同應用之間傳遞數(shù)據(jù)分蓖。
使用url scheme的第一步是在項目的info.plist文件中添加新row尔艇,命名為URL types
展開新增的字典,我們修改其中的URL Identifier以及新增加一個字段
URL Schemes漓帚。
Identifier用來跳轉(zhuǎn)后午磁,讓跳轉(zhuǎn)應用識別從哪里跳轉(zhuǎn)過來的,我們可以設置為bundleID反轉(zhuǎn)昧辽,來確保其特殊性登颓。
URL Schemes是一個數(shù)組搅荞,我們將在這個數(shù)組里面自定義自己的url schemes咕痛,這里我們填寫應用名喇嘱。最終效果如下:
接著,我們就可以在其他應用中通過openURL:方法打開我們的app腔丧。
二維碼掃描
二維碼掃描的步驟:
1作烟、創(chuàng)建設備會話對象,用來設置設備數(shù)據(jù)輸入
2衣厘、獲取攝像頭压恒,并且將攝像頭對象加入當前會話中
3怖亭、實時獲取攝像頭原始數(shù)據(jù)顯示在屏幕上
4坤检、掃描到二維碼/條形碼數(shù)據(jù)期吓,通過協(xié)議方法回調(diào)
會話對象
AVCaptureSession
的創(chuàng)建
_session = [AVCaptureSession new];
[_session setSessionPreset: AVCaptureSessionPresetHigh]; //高質(zhì)量采集
[self setupIODevice];setupIODevice
方法中懶加載方式創(chuàng)建輸入對象和輸出對象讨勤,注意必須在輸出數(shù)據(jù)對象加入到當前會話后才能設置識別的數(shù)據(jù)格式。這里設置為掃描二維碼以及條形碼
[_session addInput: self.input];
[_session addOutput: self.output];
_output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];創(chuàng)建
AVCaptureMetadataOutput
設置好掃描成功回調(diào)代理以及回調(diào)線程
_output = [AVCaptureMetadataOutput new];
[_output setMetadataObjectsDelegate: self queue: dispatch_get_main_queue()];創(chuàng)建
AVCaptureDeviceInput
輸入設備為手機攝像頭
AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
_input = [AVCaptureDeviceInput deviceInputWithDevice: device error: nil];創(chuàng)建
AVCaptureVideoPreviewLayer
對象來實時獲取攝像頭圖像谱姓,我們需要調(diào)用[self.view addSubview: self.scanView]
把攝像頭獲取的圖像實時展示在屏幕上
_scanView = [AVCaptureVideoPreviewLayer layerWithSession: self.session];
_scanView.videoGravity = AVLayerVideoGravityResizeAspectFill;
_scanView.frame = self.bounds;實現(xiàn)
captureOutput: didOutputMetadataObjects: fromConnection:
來獲取掃描得到的數(shù)據(jù)刨晴。回調(diào)參數(shù)metadataObjects中存放了掃描結果茄靠,我們需要先判斷這個數(shù)組的數(shù)據(jù)個數(shù)不為0再執(zhí)行下面的代碼:
[self stop];
AVMetadataMachineReadableCodeObject * metadataObject = metadataObjects[0];
if ([self.delegate respondsToSelector: @selector(scanView:codeInfo:)]) {
[self.delegate scanView: self codeInfo: metadataObject.stringValue];
[self removeFromSuperview];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName: LXDSuccessScanQRCodeNotification object: self userInfo: @{ LXDScanQRCodeMessageKey: metadataObject.stringValue }];
讀取二維碼信息進行應用跳轉(zhuǎn)
首先要說明的是蝶桶,二維碼并非一定要存儲應用的url scheme。例如公眾號的二維碼脐雪,雖然不知道是怎樣的數(shù)據(jù)存儲恢共,但肯定不是應用跳轉(zhuǎn)』裱可以給自己的應用指定一個二維碼數(shù)據(jù)規(guī)則拐袜,例如支付寶付款掃描是讀取商品的ID、價格等信息蹬铺,然后進行頁面跳轉(zhuǎn)付款甜攀。
這里我們使用上面設置的url scheme琐馆,我們通過制作二維碼方法來定制一個存儲應用跳轉(zhuǎn)信息的二維碼恒序,通過下面的代理創(chuàng)建一個存儲url scheme(使用url scheme的時候要注意在后面加上://后才能使用openURL進行跳轉(zhuǎn))的二維碼,這一步應該放到模擬器上面生成
- (IBAction)createBarcode:(id)sender
{
UIImage * image = [UIImage imageOfQRFromURL: @"LXDDrawLosts://" codeSize: 160.f red: 123 green: 189 blue: 229 insertImage: nil];
CGSize size = image.size;
UIImageView * imageView = [[UIImageView alloc] initWithFrame: ((CGRect){(CGPointZero), (size)})];
imageView.center = self.view.center;
imageView.image = image;
[self.view addSubview: imageView];
}
創(chuàng)建二維碼掃描控制器滋饲,然后對我們生成的二維碼進行掃描(這一步要在真機上面完成喊巍,上面url scheme的應用應當通過xcode安裝在手機上,才能完成跳轉(zhuǎn))
LXDScanCodeController * scanCodeController = [LXDScanCodeController scanCodeController];
scanCodeController.scanDelegate = self;
[self.navigationController pushViewController: scanCodeController animated: YES];
掃描成功后判斷是否可以打開跳轉(zhuǎn)呵曹,如果你的應用有一套二維碼數(shù)據(jù)存儲的規(guī)則何暮,那么在不能跳轉(zhuǎn)的時候應該按照這套規(guī)則解析數(shù)據(jù)。這里我直接在無法跳轉(zhuǎn)的情況下顯示警告框告訴用戶無法解析二維碼:
NSURL ** * url = [NSURL URLWithString: codeInfo];
if ([[UIApplication sharedApplication] canOpenURL: url]) {
[[UIApplication sharedApplication] openURL: url];
} else {
UIAlertView ** * alertView = [[UIAlertView alloc] initWithTitle: @"警告" message: [NSString stringWithFormat: @"%@:%@", @"無法解析的二維碼", codeInfo] delegate: nil cancelButtonTitle: @"確定" otherButtonTitles: nil];
[alertView show];
}
按照上面的步驟進行的話砍聊,那么在你掃完二維碼之后贰军,你的手機就會跳轉(zhuǎn)到剛才設置url scheme的應用中。
掃描優(yōu)化
上面已經(jīng)完成了二維碼的掃描功能實現(xiàn)俯树,但是現(xiàn)在你會發(fā)現(xiàn)我們在使用上面代碼進行掃描的時候贰盗,整個屏幕都是掃描范圍,這樣會影響掃描的準確性以及我們調(diào)整掃描范圍的難度陋率。
蘋果提供了一種方式讓我們規(guī)定掃描范圍:在AVCaptureMetadataOutput
中有一個叫做rectOfInterest
的CGRect類型屬性秽晚,這個屬性用來限制掃描范圍。
這個屬性的每一個值取值范圍在0~1之間菩浙,代表的是對應軸上的比例大小。最開始我以為這個是以左上角為原點陆淀,后來設置為CGRectMake(0.3, 0.35, 0.4, 0.3)
發(fā)現(xiàn)和預期的不一樣先嬉,因為這個屬性是以屏幕右上角為坐標原點,并且寬高的順序要對換過來
如圖所示浸剩,由于坐標系的不同鳄袍,原本
CGRectMake(0.3, 0.35, 0.4, 0.3)
到了新坐標系中就變成了CGRectMake(0.35, 0.3, 0.3, 0.4)
吏恭。那么大家設置成新的掃描范圍之后,重新運行掃描程序哀九,看看效果——然而搅幅,我們發(fā)現(xiàn)并不能掃描成功,這是因為這個掃描區(qū)域不僅僅是坐標系原點發(fā)生了改變息裸。如下圖所示
按照上面CGRect的設置沪编,我是想要把掃描范圍控制在屏幕x軸上面0.3-0.7,y軸上0.35-0.65之間的范圍访圃。但是在這個屬性中相嵌,width和height分別表示的是在rectOfInterest坐標中掃描矩形右下角的坐標點位置。因此批糟,這個掃描范圍應該是
CGRectMake(0.35, 0.3, 0.65, 0.7)
捏雌。除了設置好掃描范圍之內(nèi),我們還可以仿照微信的掃描纬傲,給非掃描范圍加上一層半透明的黑色layer
應用傳值
前面說過,url scheme不僅僅支持應用跳轉(zhuǎn)算墨,它還支持使用類似get請求的方式在應用間傳值汁雷。上面跳轉(zhuǎn)的url scheme是LXDDrawLosts://
,那么類似get請求挖藏,我們在這個字符串后面加上一個?
表示區(qū)分開參數(shù)和應用id厢漩,使用&
分隔不同參數(shù),然后后面按照字段名=屬性值
的方式拼湊鏈接宵膨。
比如炸宵,假設這是一個即時通訊app,那么我可以制定這樣的一個跳轉(zhuǎn)參數(shù)規(guī)則:
-
method
表示操作類型 -
userId
用戶id -
title
分享標題 -
message
分享消息 -
link_url
分享鏈接
那么土全,如果傳入的是
LXDDrawLosts://?method=addFriends&userId=10086
這可能代表的是掃描后添加id為10086的新好友涯曲。
又比如
LXDDrawLosts://?method=shareMessage&title=分享測試&message=這是林欣達的分享測試&link_url=http://www.reibang.com/users/0cf7d455eb9e/latest_articles
這代表分享信息到你的app中。這些都是我們自己的應用可以制定的規(guī)則拨黔,如果有興趣绰沥,可以新浪微博開放平臺或者騰訊開放平臺,他們的文檔中應該有url scheme的傳值標準零截。
說完了通過url scheme傳入?yún)?shù)后秃臣,怎么把這些參數(shù)取出來呢哪工?AppDelegate中提供了application:openURL: sourceApplication: annotation:
方法讓我們可以取出傳入的值弧哎。
在我們通過url scheme跳轉(zhuǎn)到本應用的時候,這個方法就會被系統(tǒng)調(diào)用偎捎。其中序攘,有兩個重要的參數(shù)需要我們知道
-
sourceApplication
這個字符串保存了跳轉(zhuǎn)方app的url Identifier
,就是上文中除了url scheme
以外的另一個字段 -
url
這個鏈接中存儲了跳轉(zhuǎn)的url scheme
以及參數(shù)列表丈牢,我們通過[url scheme]
方法獲取前者瞄沙;用[url query]
方法獲取?
之后的參數(shù)列表,然后使用字符串的分隔方法把這些數(shù)據(jù)讀取出來
單純的二維碼數(shù)據(jù)并沒有過于強大的功能,但結合了url scheme的跳轉(zhuǎn)機制后遂铡,二維碼能夠幫助我們的應用獲得更加強大的能力扒接,使得我們的應用之間有了更多聯(lián)系。
文集:iOS開發(fā)
本文demo:二維碼掃描集成
轉(zhuǎn)載表明鏈接:http://sindrilin.com/ios-dev/2015/11/01/二維碼掃描和應用跳轉(zhuǎn).html