鴻蒙第三方元件——SwipeCaptcha滑動拼圖驗證元件

前言

基於安卓平臺的滑動拼圖驗證元件SwipeCaptcha(https://github。com/mcxtzhang/SwipeCaptcha),實現了其核心功能的鴻蒙化遷移和重構,程式碼已經開源到(https://gitee。com/isrc_ohos/SwipeCaptcha),歡迎各位下載使用並提出寶貴意見!

背景

在頁面登入或者註冊的時候,為了確保不是機器人操作,會讓使用者手動驗證。驗證方式分為滑動拼圖驗證和滑動驗證兩種。本文的SwipeCaptcha元件可以實現滑動拼圖的驗證方式,操作簡單,安全性強,被眾多APP使用。

元件效果展示

鴻蒙系統的SwipeCaptcha元件在使用時,有兩個較為重要的圖片:滑塊和原圖。這兩張圖片被放置於同一水平線上,使用者拖動滑塊至原圖處,誤差在一定範圍內,即可驗證成功。每次呼叫SwipeCaptcha元件,滑塊和原圖的位置都會發生隨機變化,登入時被暴力破解的難度增加,安全性較高。

在SwipeCaptcha元件的驗證介面,還有當前進度值和驗證狀態的描述。當前進度值表示滑塊在水平方向的滑動進度,進度為100時,表示滑塊滑至最右端。進度值下方展示的是當前的驗證狀態,可分為:“開始”、“驗證失敗,請重新驗證三種狀態”、“驗證成功”。下面依次展示SwipeCaptcha元件拼圖驗證失敗和成功的效果圖。

1、驗證失敗效果

使用者未將滑塊拖至原圖處,導致滑塊與原圖的位置誤差較大,驗證失敗。

鴻蒙第三方元件——SwipeCaptcha滑動拼圖驗證元件

圖1 驗證失敗效果

2、驗證成功效果

使用者拖動滑塊至原圖處,誤差在一定範圍內,驗證成功。

鴻蒙第三方元件——SwipeCaptcha滑動拼圖驗證元件

圖2 驗證成功效果

Sample解析

Sample主要包含以下四個部分:1)拼圖背景匯入手機。2)裁剪滑塊。3)繪製滑塊。4)驗證拼圖是否成功。下面將透過具體步驟對上述四個部分進行詳解。

1、資料初始化

本步驟包含三個部分的資料設定:(1)獲取手機螢幕寬度資訊;(2)設定進度值和驗證狀態的初始提示文字,如“當前進度值”、“請滑動滑塊驗證”;(3)初始化畫筆資訊,定義畫筆屬性;

//獲取手機螢幕寬度displayAttributes。widthDisplayManager displayManager = DisplayManager。getInstance();Display display = displayManager。getDefaultDisplay(this)。get();DisplayAttributes displayAttributes = display。getAttributes();windowWidth = displayAttributes。width;// 進度值初始化text = new Text(this);text。setMarginTop(800);// 距離頂端邊界的距離text。setText(“當前進度值”+ progress);// 設定文字text。setTextSize(100);// 設定字號myLayout。addComponent(text);// 新增進佈局中// 驗證狀態初始化text2 = new Text(this);text2。setMarginTop(1000);text2。setText(“請滑動滑塊驗證”);text2。setTextSize(100);myLayout。addComponent(text2);//初始化畫筆的資訊mPaint = new Paint();mPaint。setColor(Color。BLACK);//定義顏色mPaint。setAntiAlias(true);//定義虛實線mPaint。setStrokeWidth(5f);//定義寬度mPaint。setStyle(Paint。Style。STROKE_STYLE);//定義繪圖方式

2、背景圖片繪製

用手機螢幕的寬度除以背景圖片的寬度,得到背景圖片的縮放比例,當該圖片顯示在手機中,按照此比例縮放可與螢幕同寬。該比例用於背景圖片適配不同型號的手機螢幕。

//背景圖片的縮放比例float ratio = (float) windowWidth/(float) img。getImageInfo()。size。width;//背景圖片繪製Component image = new Component(this);Component。DrawTask drawTask = new Component。DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { //按照比例進行縮放 canvas。scale(ratio , ratio); //繪圖 canvas。drawPixelMapHolder(pixelMapHolder, 0, 0, new Paint()); }};image。addDrawTask(drawTask);myLayout。addComponent(image);

3。 確定滑塊和原圖的位置

鴻蒙第三方元件——SwipeCaptcha滑動拼圖驗證元件

圖3 滑塊和原圖的位置示意

puzzleWidth為滑塊或者原圖的寬度;top為隨機數值,表示滑塊或者原圖的上邊距離背景圖片上邊的距離;puzzel2left也為隨機數值,表示原圖左邊距離背景圖片左邊的距離。有了以上三個變數可以確定元件中滑塊和原圖的初始位置和大小(滑塊初始時位於螢幕的最左側)。下面介紹上述屬性是如何計算出來的。

//puzzleWidth為螢幕寬度的1/6puzzleWidth = windowWidth/6;//top為圖片縮放後高度與摳圖高度之差再乘以隨機數top = (float) Math。random()*(img。getImageInfo()。size。height*ratio - puzzleWidth);//原圖位置一定在滑塊位置右面//螢幕寬度減去兩個拼圖寬度 *隨機數,後向右平移一個滑塊的長度puzzel2left = ((windowWidth -puzzleWidth*2) * (float)Math。random()) + puzzleWidth;

4。 獲取滑塊

本步驟需要根據原圖的位置,解碼出一個圖片作為滑塊。首先設定滑塊的形狀為矩形,依據上述的puzzel2left、puzzleWidth屬性,確定矩形所在區域,依據縮放比例,將矩形區域對映為原比例影象,並對此影象進行解碼,得到滑塊影象資料。

PixelMap puzzlePixelMap = getPuzzlePixelMap(this , ResourceTable。Media_longa , new Rect((int)(puzzel2left/ratio), (int) (top/ratio), (int) (puzzleWidth/ratio) , (int) (puzzleWidth/ratio)));PixelMapHolder pixelMapHolder1 = new PixelMapHolder(puzzlePixelMap);

5。繪製滑塊

滑塊透過畫筆來繪製,其位置應該根據滑動進度條的進度來移動,並且要對不同手機螢幕的大小進行適配。同時,為了和使用者友好的互動,我們還需要為滑塊繪製一個邊框,告知使用者這個邊框所在就是滑塊(原圖也需要繪製邊框,原理相同)。繪製滑塊和邊框的程式碼如下:

//繪製滑塊Component。DrawTask puzzelDrawTask = new Component。DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { Paint paint = new Paint();//移動小滑塊拼圖 canvas。translate(slider。getProgress()*displayAttributes。width /100 , top);//進行適當比例縮放 canvas。scale(ratio , ratio); canvas。drawPixelMapHolder(pixelMapHolder1 , 0 , 0 , paint); }};//繪製滑塊邊框Component puzzleFrame = new Component(this);Component。DrawTask drawTask2 = new Component。DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { //方框左側位置 float left = slider。getProgress()*windowWidth /100; //繪製邊框的左邊 canvas。drawLine(new Point(left , top), new Point(left, top + puzzleWidth), mPaint); //繪製邊框的上邊 canvas。drawLine(new Point(left, top), new Point(left + puzzleWidth, top), mPaint); //繪製邊框的右邊 canvas。drawLine(new Point(left + puzzleWidth, top), new Point(left + puzzleWidth, top + puzzleWidth), mPaint); //繪製邊框的下邊 canvas。drawLine(new Point(left, top + puzzleWidth), new Point(left + puzzleWidth, top + puzzleWidth), mPaint); }};

6。 進度條滑動更新

為進度條設定監聽,拖動進度條會引起三處更新:(1)滑塊位置和滑塊邊框位置的更新;(2)進度值的更新;(3)驗證狀態的更新。在驗證狀態的更新中,需要對使用者拖動進度條結束時的驗證狀態進行判斷,滑塊和原圖的位置差距是否在誤差範圍內,如果在範圍內,則顯示驗證成功,如果不在誤差範圍內,則顯示驗證失敗,提示需要重新驗證。

//設定進度條監聽slider。setValueChangedListener(new Slider。ValueChangedListener() { @Override//拖動進度條引起的更新public void onProgressUpdated(Slider slider, int i, boolean b) { //滑塊的位置更新 puzzle。invalidate(); //滑塊邊框位置的更新 puzzleFrame。invalidate(); //進度值更新text。setText(“當前進度值 : ” + slider。getProgress()); }}//當用戶開始滑動進度條時,驗證狀態變為“開始”字樣。public void onTouchStart(Slider slider) { //開始拖動的方法 text2。setText(“開始”);} //判斷滑塊左側邊的位置和原圖的左側邊的位置是否在誤差內public void onTouchEnd(Slider slider) { if(((slider。getProgress()*windowWidth /100)<(puzzel2left + puzzleWidth/10))&&((slider。getProgress()*windowWidth /100)>(puzzel2left - puzzleWidth/10))) { text2。setText(“驗證成功”); }else { text2。setText(“驗證失敗,請重新驗證”); slider。setProgressValue(10); }}

專案貢獻人

趙柏屹 鄭森文 朱偉 陳美汝 張馨心