日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

移动端(ios and android)长按识别二维码(含js与原生互调)

發(fā)布時(shí)間:2024/3/24 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 移动端(ios and android)长按识别二维码(含js与原生互调) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這篇文章就整理下移動(dòng)端長按識(shí)別二維碼的實(shí)現(xiàn)吧!實(shí)現(xiàn)方式可以分為三種

一、長按原生控件,直接獲取控件中的圖片數(shù)據(jù)(src或background)

二、長按原生控件,截圖識(shí)別

三、長按web中的圖片,app識(shí)別其中的二維碼(js互調(diào))


第一二種好像沒多少可以說的,但還是按照順序來吧!首先先說下使用的庫,ios使用原生二維碼識(shí)別庫(好像是ios7之后才有的),然后說是WKWebView比UIWebView優(yōu)化了很多 東西,也解決了內(nèi)存泄漏的問題那么js交互的部分我們就用WKWebView吧(說到這里必須吐槽下android的webView內(nèi)存泄漏問題,一個(gè)字坑)。android沒原生的,我了解的比較大眾的就zxing和zbar,經(jīng)過測試發(fā)現(xiàn)在二維碼占圖片的比例較小識(shí)別時(shí)zbar的識(shí)別比zxing好一些,而且zxing使用截圖的方案實(shí)現(xiàn)時(shí)當(dāng)二維碼放在屏幕的底部時(shí)識(shí)別不出來,所以這里就直接只貼zbar的代碼吧!

然后呢因?yàn)槭菍懙膁emo,代碼是沒優(yōu)化過的,怎么方便怎么來,實(shí)際使用還是得根據(jù)自己的需要優(yōu)化一下,個(gè)人覺得重要的是實(shí)現(xiàn)方案和思路。

一、長按原生控件,直接獲取控件中的圖片數(shù)據(jù)(src或background)

這里基本上等于在介紹,二維碼識(shí)別的使用了。

(1)android

獲取圖片android就比較簡單了。長按事件就不說了,圖片通常會(huì)用ImageView,直接獲取src就行了,特殊點(diǎn)的放background,那么就獲取background就好了。直接貼代碼吧!

//src Bitmap mBitmap=((BitmapDrawable) imageView.getDrawable()).getBitmap();//background mBitmap=((BitmapDrawable) imageView.getBackground()).getBitmap();
下面就是關(guān)鍵zbar 識(shí)別圖片中二維碼的代碼了

----------------------------------------------- public String parseRQ(Bitmap bitmap) {String text = null;ImageScanner scanner=new ImageScanner();scanner.setConfig(0, Config.X_DENSITY,3);scanner.setConfig(0, Config.Y_DENSITY, 3);//設(shè)置掃描的圖片Image barcode = new Image(bitmap.getWidth(), bitmap.getHeight(), "Y800");//設(shè)置掃描的圖片的區(qū)域,因?yàn)槲覀儾恢蓝S碼在哪,所以直接設(shè)置整張圖片barcode.setCrop(0, 0, bitmap.getWidth(), bitmap.getHeight());int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];byte[] bitmapPixels =new byte[bitmap.getWidth() * bitmap.getHeight()];bitmap.getPixels(data, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());for (int i = 0; i < data.length; i++) {bitmapPixels[i] = (byte) data[i];}barcode.setData(bitmapPixels);//識(shí)別圖片中的二維碼,result是二維碼的個(gè)數(shù)(這點(diǎn)比zxing好,zxing只獲取從左上開始找到的第一個(gè),不過也有可能是我調(diào)用的api不對(duì)也不一定)int result = scanner.scanImage(barcode);if (result != 0){SymbolSet syms = scanner.getResults();for (Symbol sym : syms){text=sym.getData().trim();//我們只獲取第一個(gè)非空二維碼,習(xí)慣性判空,沒測過幾個(gè)空字符串可不可以生成二維碼if(!text.isEmpty()){break;}}}return text;}--------------------------------------------------

拿到解碼后的數(shù)據(jù),就可以根據(jù)需求取實(shí)現(xiàn)功能了。

(2)ios

ios獲取UIImageView的圖片更容易直接就是imageView.image就可以了,原生識(shí)別二維碼的操作也簡單,個(gè)人覺得設(shè)置長按事件比這兩個(gè)加起來都麻煩點(diǎn)。所以這里主要就是設(shè)置長按事件的代碼了。貼碼。

//創(chuàng)建長按,imageLongClick即為長按響應(yīng)的函數(shù) UILongPressGestureRecognizer *longClick=[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(imageLongClick:)];//觸摸點(diǎn)數(shù),即多少手指點(diǎn)擊longClick.numberOfTouchesRequired=1;//開啟觸發(fā)事件處理imageView.userInteractionEnabled=YES;//imageView添加長按事件[imageView addGestureRecognizer:longClick];

ios原生識(shí)別二維碼,比zxing和zbar都簡單多了,當(dāng)然這沒做優(yōu)化策略的,android zbar那那個(gè)代碼也一樣

---------------------------------------------- -(void)imageLongClick:(UILongPressGestureRecognizer *)sender{//按下時(shí)if ([sender state]==UIGestureRecognizerStateBegan) {NSLog(@"image long click....");//創(chuàng)建識(shí)別器CIDetector *detector=[CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:nil];//image轉(zhuǎn)為CGImage進(jìn)行識(shí)別,結(jié)果為所有二維碼結(jié)果的對(duì)象數(shù)組NSArray *results=[detector featuresInImage:[CIImage imageWithCGImage:[self snapshotView].CGImage]];if (results.count>0) {//這里只拿第一個(gè)CIQRCodeFeature *feature=[results firstObject];//feature.messageString即為解碼后的字符串,這里直接打開瀏覽器[[UIApplication sharedApplication] openURL:[NSURL URLWithString:feature.messageString]];}else{NSLog(@"找不到二維碼");}} } --------------------------------------------


在此直接獲取控件的圖片直接識(shí)別的就這樣結(jié)束了,如果要獲取相冊的也一樣,只需將從相冊獲取到的圖片轉(zhuǎn)為對(duì)應(yīng)的Bitmap(ios UIImage),其他的都不變就可。

這里需注意的是背景色如果是透明色是無法識(shí)別出來的,所以如果二維碼的來源是自己app的這種方式就很好了,如果是用戶上傳的建議用第二種方式,不可保證不會(huì)有哪個(gè)坑上傳個(gè)透明背景的圖片或上傳個(gè)長圖。


二、長按原生控件,截圖識(shí)別

長按事件和識(shí)別二維碼的代碼是一樣的,就不重復(fù),即獲取到截屏的圖片后調(diào)用識(shí)別的方法就可以了,所以這里就只剩截屏功能的代碼了,一樣直接上代碼

(1)android

----------------------------------------------------- //其實(shí)這里直接傳個(gè)View進(jìn)來也是可以的,比如第三種的長按網(wǎng)頁的就可以將WebView傳就來就可以了 public Bitmap snapshotView(Window window) {if (window != null) {//找到當(dāng)前頁面的根布局View view = window.getDecorView().getRootView();//獲取當(dāng)前屏幕的大小int width = view.getWidth();int height = view.getHeight();//設(shè)置緩存view.setDrawingCacheEnabled(true);view.buildDrawingCache();/*1、從緩存中獲取當(dāng)前屏幕的圖片,創(chuàng)建一個(gè)DrawingCache的拷貝,因?yàn)镈rawingCache得到的位圖在禁用后會(huì)被回收*2、這里的88是去掉無用的部分即你確定是不會(huì)有二維碼的部分(當(dāng)然不做任何操作也是可以的),這里直接寫死是狀態(tài)欄的高度,*實(shí)際真正使用不會(huì)這么寫,而是是去獲取狀態(tài)欄的高度(這里懶就不寫了),我記得如果直接是控件調(diào)用buildDrawingCache*是該控件當(dāng)前顯示在屏幕上的部分就不用減去狀態(tài)欄的高度了*/Bitmap temBitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, 88, width, height - 88);//禁用DrawingCahce否則會(huì)影響性能 ,而且不禁止會(huì)導(dǎo)致每次截圖到保存的是緩存的位圖view.destroyDrawingCache();view.setDrawingCacheEnabled(false);return temBitmap;}return null;} ---------------------------------------------------

(2)ios

--------------------------------------------- //跟android一樣這里的UIWindow也可以改成UIView,函數(shù)接受UIView的參數(shù),外部就可以直接調(diào)用截取指定控件顯示在屏幕的部分截圖了 - (UIImage *)snapshotView {UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];//這里只獲取大小,所以bounds還是frame都是一樣的CGRect rect = [keyWindow bounds];if(UIGraphicsBeginImageContextWithOptions != NULL){//iphone4之后采用Retina屏幕調(diào)用這個(gè)(不知道有沒有記反,也有其他的截圖方式,只是我就記得這種)UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0);} else {UIGraphicsBeginImageContext(rect.size);}CGContextRef context = UIGraphicsGetCurrentContext();[keyWindow.layer renderInContext:context];UIImage *img = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return img; } -----------------------------------------------------------------------------------------------


三、長按web中的圖片,app識(shí)別其中的二維碼

這里也是截圖實(shí)現(xiàn),為什么不是拿原始圖片識(shí)別,1是上面說的有可能是長圖或背景透明,2是截圖免下載,在速度體驗(yàn)上好點(diǎn)。我記得微信也是這樣實(shí)現(xiàn)的,在哪提過我忘了。

既然涉及js,那我們就必須先來段js呀,js長按圖片功能代碼(本來是想用jquery的,但想想網(wǎng)頁不一定是自己的,有可能是別人的靜態(tài)網(wǎng)頁,根本沒導(dǎo)入jquery庫,而直接 注入<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>的形式是會(huì)有跨域的問題的,所以不用jquery,直接寫好了,代碼量其實(shí)也差不多):

----------------------------------------------------- //閉包,這里個(gè)人當(dāng)成跟java的匿名對(duì)象差不多記憶 (function () {//獲取所有圖片標(biāo)簽var allImage = document.getElementsByTagName("img");var img;for (var i = 0; i < allImage.length; i++) {img = allImage[i];//添加觸摸事件img.addEventListener('touchstart', function(event) {touch = event.touches[0];startevent = event;//保存觸摸點(diǎn)的x,y軸startX = Number(touch.pageX);startY = Number(touch.pageY);//設(shè)置定時(shí)器,js沒長按事件,就是使用定時(shí)器實(shí)現(xiàn)的,800毫秒后觸發(fā),img.src為圖片地址,這里可以拿到后做保存圖片發(fā)大圖等功能timeout = setTimeout('longClick('+img.src+');', 800);});//移動(dòng)事件img.addEventListener('touchmove', function(event) {touch = event.touches[0];scx = Math.abs(Number(touch.pageX) - startX);scy = Math.abs(Number(touch.pageY) - startY);//過濾掉移動(dòng)事件,不這樣做,當(dāng)你手指放在這個(gè)圖片往上或往下劃的時(shí)候,800毫秒后也會(huì)觸發(fā)長按事件,精確度可以自己調(diào)if (scx > 10 || scy > 10) { //取消定時(shí)器clearTimeout(timeout);} else {//相當(dāng)android的攔截分發(fā)event.preventDefault();}});//手指放開時(shí)取消定時(shí)器img.addEventListener('touchend', function(event) {clearTimeout(timeout);});}})();//立即執(zhí)行 -------------------------------------------------------

app要做的就是兩件事,1、將截圖識(shí)別二維碼對(duì)象注入js中。2、網(wǎng)頁加載結(jié)束后,加載執(zhí)行上面那個(gè)js函數(shù)代碼即可。

(1)android

android相對(duì)簡單點(diǎn),創(chuàng)建注入對(duì)象

--------------------------------------------------- public class DemoJSBridge{@JavascriptInterfacepublic void longClickImage(String imgSrc){//調(diào)用截圖識(shí)別二維碼代碼} }//注入 wb.addJavascriptInterface(new DemoJSBridge(), "demoJSBridge");---------------------------------------------------
這樣就可以注入代碼了,其他功能直接在類中加方法即可,而前端js調(diào)用則是

//對(duì)象是注入到window對(duì)象中的,所以是window.對(duì)象.方法 window.demoJSBridge.longClickImage(img.src);
所以上面的js函數(shù)中的'longClick('+img.src+');'改掉,然后頁面加載完成后注入執(zhí)行即可。即

------------------------------------------------------wb.setWebViewClient(new WebViewClient() {@Overridepublic void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);//加載js,而我們那個(gè)js函數(shù)是立即執(zhí)行的,所以一加載就會(huì)自動(dòng)執(zhí)行,getQRJs()即為上面js函數(shù)的String格式wb.loadUrl("javascript:" + getQRJs());}}); ------------------------------------------------------

(2)ios個(gè)人覺得麻煩點(diǎn),但安全點(diǎn)

注入js對(duì)象

------------------------------------------------------------------------- //構(gòu)建script對(duì)象,配置頁面加載完成后加載上面js函數(shù)的并執(zhí)行,getJSString即為上面js函數(shù)的字符串, //WKUserScriptInjectionTimeAtDocumentEnd頁面加載結(jié)束后注入 WKUserScript *script=[[WKUserScript alloc] initWithSource:[self getJSString] injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];//WKWebView配置對(duì)象WKWebViewConfiguration *config=[[WKWebViewConfiguration alloc] init];config.preferences=[WKPreferences new];//允許執(zhí)行javaScriptconfig.preferences.javaScriptEnabled=YES;//WKWebView自帶長按事件,會(huì)攔截掉我們添加的事件,所以屏蔽掉NSMutableString *javascript = [NSMutableString string];//禁止webkitTouchCallout[javascript appendString:@"document.documentElement.style.webkitTouchCallout='none';"];[javascript appendString:@"document.documentElement.style.webkitUserSelect='none';"];//禁止選擇WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];[config.userContentController addUserScript:noneSelectScript];[config.userContentController addUserScript: script];//注入對(duì)象addScriptMessageHandler響應(yīng)處理者self[config.userContentController addScriptMessageHandler:self name:@"demoJSBridge"];WKWebView *webView=[[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; ---------------------------------------------------------------------------------

然后注意

1、script即我們上面代碼中加載js函數(shù)的形式也可以用第二種方式,跟android的差不多,即

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{[self.webView evaluateJavaScript:[self getJSString] completionHandler:nil]; }?

2、實(shí)現(xiàn)協(xié)議WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler,第一個(gè)頁面加載進(jìn)度等事件的回調(diào)。第二個(gè)js對(duì)話框的回調(diào),WKWebView把js的對(duì)話框就是alert()這些給屏蔽了,我們需實(shí)現(xiàn)WKUIDelegate協(xié)議自己去彈窗。第三個(gè)js調(diào)用原生的方法。


3、WKWebView注入的對(duì)象跟android和UIWebView都不一樣了,他放在了window.webkit.messageHandlers里,所以前端js調(diào)用時(shí)為

window.webkit.messageHandlers.對(duì)象名.postMessage(參數(shù));所以所以上面的js函數(shù)中的'longClick('+img.src+');'改掉,參數(shù)直接傳js對(duì)象,如{functionName:"longClickImage",data:img.src},實(shí)現(xiàn),如果為減少與android的差異性,android也可以改為只有postMessage(String msg)方法,然后根據(jù)functionName去執(zhí)行對(duì)應(yīng)的功能。js對(duì)象傳到app后,ios會(huì)自動(dòng)轉(zhuǎn)為字典,android為json字符串,自己轉(zhuǎn)成json就可以了。

個(gè)人理解是WKWebView取消了直接注入對(duì)象了,即沒有將self注入到j(luò)s中,而是于注入一個(gè)假對(duì)象,里面只有postMessage函數(shù),當(dāng)js調(diào)用這個(gè)函數(shù)時(shí)他對(duì)應(yīng)的再去調(diào)用原生的回調(diào)。


4、響應(yīng)js調(diào)用事件,即實(shí)現(xiàn)WKScriptMessageHandler協(xié)議

------------------------------------------------------------ - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{//message中的name即為注入的對(duì)象名,body為傳過來的數(shù)據(jù)if ([message.name isEqualToString:@"demoJSBridge"]) {//js對(duì)象傳過來后會(huì)自動(dòng)轉(zhuǎn)為字典NSDictionary *d=message.body;if ([@"longClickImage" isEqualToString:[d objectForKey:@"functionName"]]) {//調(diào)用截屏,識(shí)別二維碼方法}} } -------------------------------------------------------------------

理論上js與原生的互調(diào)就這樣可以了,但為了保險(xiǎn)一點(diǎn)的話,原生接到j(luò)s的調(diào)用以后再回調(diào)一下js比較好一點(diǎn),因?yàn)橛锌赡苡行┕δ躩s需要app回傳數(shù)據(jù)做下一步操作。相當(dāng)于待人接物而言你叫我做一件事,做好了還是做不了,我得告知你一下,做個(gè)有交代有責(zé)任的人。


這篇好像有點(diǎn)長,寫得不好的地方還多請(qǐng)見諒,也可在評(píng)論指導(dǎo)一下。








總結(jié)

以上是生活随笔為你收集整理的移动端(ios and android)长按识别二维码(含js与原生互调)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。