Android實(shí)現(xiàn)人臉支付的示例代碼
效果展示
人臉支付效果視頻
密碼框輸入支付效果視頻
因?yàn)槊艽a支付時(shí)會(huì)調(diào)起系統(tǒng)安全鍵盤,開啟自動(dòng)保護(hù)功能,防止泄露,會(huì)導(dǎo)致輸入密碼時(shí)錄屏黑屏,故使用另一臺(tái)手機(jī)拍攝。
功能實(shí)現(xiàn)
人臉支付
API初始化
ftEngine = new FaceEngine(); ftInitCode = ftEngine.init(this, DetectMode.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(this), 16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_DETECT); frEngine = new FaceEngine(); frInitCode = frEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY, 16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_RECOGNITION); flEngine = new FaceEngine(); flInitCode = flEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY, 16, MAX_DETECT_NUM, FaceEngine.ASF_LIVENESS);
人臉特征提取
private void searchFace(final FaceFeature frFace, final Integer requestId) { Observable.create(new ObservableOnSubscribe<CompareResult>() { @Override public void subscribe(ObservableEmitter<CompareResult> emitter) { CompareResult compareResult = FaceServer.getInstance().getTopOfFaceLib(frFace); emitter.onNext(compareResult); } }) .subscribeOn( Schedulers.computation()) .observeOn( AndroidSchedulers.mainThread()) .subscribe(new Observer<CompareResult>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(CompareResult compareResult) { if (compareResult == null || compareResult.getUserName() == null) { requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED); faceHelper.setName(requestId, "VISITOR " + requestId); return; } if (compareResult.getSimilar() > SIMILAR_THRESHOLD) { boolean isAdded = false; if (compareResultList == null) { requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED); faceHelper.setName(requestId, "VISITOR " + requestId); return; } for (CompareResult compareResult1 : compareResultList) { if (compareResult1.getTrackId() == requestId) { isAdded = true; break; } } if (!isAdded) { //對(duì)于多人臉?biāo)阉?,假如最大顯示數(shù)量為 MAX_DETECT_NUM 且有新的人臉進(jìn)入,則以隊(duì)列的形式移除 if (compareResultList.size() >= MAX_DETECT_NUM) { compareResultList.remove(0); adapter.notifyItemRemoved(0); } //添加顯示人員時(shí),保存其trackId compareResult.setTrackId(requestId); compareResultList.add(compareResult); adapter.notifyItemInserted(compareResultList.size() - 1); } requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED); faceHelper.setName(requestId, getString(R.string.recognize_success_notice, compareResult.getUserName())); } else { faceHelper.setName(requestId, getString(R.string.recognize_failed_notice, "NOT_REGISTERED")); retryRecognizeDelayed(requestId); } }
返回支付結(jié)果
根據(jù)匹配人臉注冊(cè)時(shí)所獲取的trackid,判斷識(shí)別結(jié)果
Integer recognizeStatus = requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId());
根據(jù)返回碼修改識(shí)別框顏色,并修改跳轉(zhuǎn)狀態(tài)的值
if (recognizeStatus != null) { handler.sendEmptyMessageDelayed( 1,1000 ); if (recognizeStatus == RequestFeatureStatus.FAILED) { color = RecognizeColor.COLOR_FAILED; returnFlag = false; } if (recognizeStatus == RequestFeatureStatus.SUCCEED) { color = RecognizeColor.COLOR_SUCCESS; returnFlag = true; } }
利用異步通信進(jìn)行延遲跳轉(zhuǎn)
Handler handler = new Handler( ){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage( msg ); if (msg.what == 1){ CountDown(); handler.sendEmptyMessageDelayed( 1,1000 ); } } };
密碼框輸入支付
自定義密碼輸入框控件
public class PayPwdEditText extends RelativeLayout { private EditText editText; //文本編輯框 private Context context; private LinearLayout linearLayout; //文本密碼的文本 private TextView[] textViews; //文本數(shù)組 private int pwdlength = 6; //密碼長(zhǎng)度, 默認(rèn)6 private OnTextFinishListener onTextFinishListener; public PayPwdEditText(Context context) { this(context, null); } public PayPwdEditText(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PayPwdEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; } /** * @param bgdrawable 背景drawable * @param pwdlength 密碼長(zhǎng)度 * @param splilinewidth 分割線寬度 * @param splilinecolor 分割線顏色 * @param pwdcolor 密碼字體顏色 * @param pwdsize 密碼字體大小 */ public void initStyle(int bgdrawable, int pwdlength, float splilinewidth, int splilinecolor, int pwdcolor, int pwdsize) { this.pwdlength = pwdlength; initEdit(bgdrawable); initShowInput(bgdrawable, pwdlength, splilinewidth, splilinecolor, pwdcolor, pwdsize); } /** * 初始化編輯框 * @param bgcolor */ private void initEdit(int bgcolor) { editText = new EditText(context); editText.setBackgroundResource(bgcolor); editText.setCursorVisible(false); editText.setTextSize(0); //設(shè)置為密文輸入模式和數(shù)字 editText.setInputType( InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER); //設(shè)置輸入長(zhǎng)度為6 editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(pwdlength)}); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { Editable etext = editText.getText(); Selection.setSelection(etext, etext.length()); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { initDatas(s); if(s.length() == pwdlength) { if(onTextFinishListener != null) { onTextFinishListener.onFinish(s.toString().trim()); } } } }); LayoutParams lp = new LayoutParams( LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); lp.addRule( RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); addView(editText, lp); } /** * @param bgcolor 背景drawable * @param pwdlength 密碼長(zhǎng)度 * @param slpilinewidth 分割線寬度 * @param splilinecolor 分割線顏色 * @param pwdcolor 密碼字體顏色 * @param pwdsize 密碼字體大小 */ public void initShowInput(int bgcolor, int pwdlength, float slpilinewidth, int splilinecolor, int pwdcolor, int pwdsize) { //添加密碼框父布局 linearLayout = new LinearLayout(context); linearLayout.setBackgroundResource(bgcolor); LayoutParams layoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); linearLayout.setLayoutParams(layoutParams); linearLayout.setOrientation( LinearLayout.HORIZONTAL); addView(linearLayout); //添加密碼框 textViews = new TextView[pwdlength]; LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT); params.weight = 1; params.gravity = Gravity.CENTER; LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(dip2px(context, slpilinewidth), LayoutParams.MATCH_PARENT); for(int i = 0; i < textViews.length; i++) { final int index = i; TextView textView = new TextView(context); textView.setGravity( Gravity.CENTER); textViews[i] = textView; textViews[i].setTextSize(pwdsize); textViews[i].setTextColor(context.getResources().getColor(pwdcolor)); textViews[i].setInputType( InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER); linearLayout.addView(textView, params); if(i < textViews.length - 1) { View view = new View(context); view.setBackgroundColor(context.getResources().getColor(splilinecolor)); linearLayout.addView(view, params2); } } } /** * 是否顯示明文 * @param showPwd */ public void setShowPwd(boolean showPwd) { int length = textViews.length; for(int i = 0; i < length; i++) { if (showPwd) { textViews[i].setTransformationMethod( PasswordTransformationMethod.getInstance()); } else { textViews[i].setTransformationMethod( HideReturnsTransformationMethod.getInstance()); } } } /** * 設(shè)置顯示類型 * @param type */ public void setInputType(int type) { int length = textViews.length; for(int i = 0; i < length; i++) { textViews[i].setInputType(type); } } /** * 清除文本框 */ public void clearText() { editText.setText(""); for(int i = 0; i < pwdlength; i++) { textViews[i].setText(""); } } public void setOnTextFinishListener(OnTextFinishListener onTextFinishListener) { this.onTextFinishListener = onTextFinishListener; } /** * 根據(jù)輸入字符,顯示密碼個(gè)數(shù) * @param s */ public void initDatas(Editable s) { if(s.length() > 0) { int length = s.length(); for(int i = 0; i < pwdlength; i++) { if(i < length) { for(int j = 0; j < length; j++) { char ch = s.charAt(j); textViews[j].setText( String.valueOf(ch)); } } else { textViews[i].setText(""); } } } else { for(int i = 0; i < pwdlength; i++) { textViews[i].setText(""); } } } public String getPwdText() { if(editText != null) return editText.getText().toString().trim(); return ""; } public static int dip2px(Context context, float dipValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); } public interface OnTextFinishListener { void onFinish(String str); } public void setFocus() { editText.requestFocus(); editText.setFocusable(true); showKeyBord(editText); } /** * 顯示鍵盤 * @param view */ public void showKeyBord(View view) { InputMethodManager imm = (InputMethodManager) context.getSystemService( Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, InputMethodManager.SHOW_FORCED); } }
初始化控件
分別對(duì)應(yīng)密碼框背景、密碼位數(shù)、分割線寬度、分割線顏色、字體顏色、字體大小
mPayPwdEditText.initStyle( R.drawable.bg_paypassword_style,6,0.8f,R.color.colorWhite,R.color.colorWhite,35);
布局內(nèi)用法
<com.example.PayPackage.PayPwdEditText android:id="@+id/payPassWordEditText" android:layout_width="match_parent" android:layout_marginTop="20dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_height="35dp"/>
密碼匹配
對(duì)控件進(jìn)行輸入事件監(jiān)聽,采用測(cè)試密碼用例:123456,與回調(diào)接口所攜帶的數(shù)據(jù)進(jìn)行匹配。
mPayPwdEditText.setOnTextFinishListener( new PayPwdEditText.OnTextFinishListener() { @Override public void onFinish(String str) { if (str.equals( "123456" )) { startActivity( new Intent( OrderInterface.this,PaySuccess.class ) ); }else { if (PassWordError == null) { PassWordError = new Toast( OrderInterface.this ); View view = LayoutInflater.from( OrderInterface.this ).inflate( R.layout.passworderror,null,false ); ErrorTips = view.findViewById( R.id.ErrorTips ); PassWordError.setView( view ); //PassWordError.setGravity( Gravity.CENTER,0, ResHelper.dipToPx(OrderInterface.this, -100) ); } PassWordError.show(); mPayPwdEditText.clearText(); } } } );
其內(nèi)部是對(duì)EditText控件進(jìn)行輸入事件監(jiān)聽。然后通過比對(duì)輸入字符串長(zhǎng)度與密碼長(zhǎng)度,然后返回其輸入的字符串
@Override public void afterTextChanged(Editable s) { initDatas(s); if(s.length() == pwdlength) { if(onTextFinishListener != null) { onTextFinishListener.onFinish(s.toString().trim()); } } }
尾言
此人臉識(shí)別API采用虹軟ArcSoft
到此這篇關(guān)于Android實(shí)現(xiàn)人臉支付的文章就介紹到這了,更多相關(guān)Android 人臉支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android入門之系統(tǒng)設(shè)置Configuration類的使用教程
這篇文章主要給大家介紹一下Configuration類的使用,Configuration類是用來描述手機(jī)設(shè)備的配置信息的,比如屏幕方向,?觸摸屏的觸摸方式等,感興趣的可以了解一下2022-12-12簡(jiǎn)單實(shí)現(xiàn)Android學(xué)生管理系統(tǒng)(附源碼)
這篇文章主要介紹了如何簡(jiǎn)單實(shí)現(xiàn)Android學(xué)生管理系統(tǒng),特別適合計(jì)算機(jī)專業(yè)的即將畢業(yè)的同學(xué)學(xué)習(xí)借鑒制作學(xué)生管理系統(tǒng),感興趣的小伙伴們可以參考一下2015-12-12Android開發(fā)中Intent傳遞對(duì)象的方法分析
這篇文章主要介紹了Android開發(fā)中Intent傳遞對(duì)象的方法,結(jié)合實(shí)例分析了Intent傳遞對(duì)象所涉及的具體方法、實(shí)現(xiàn)步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-02-02Android實(shí)現(xiàn)商城購(gòu)物車功能的實(shí)例代碼
最近公司項(xiàng)目做商城模塊,需要實(shí)現(xiàn)購(gòu)物車功能,主要實(shí)現(xiàn)了單選、全選,金額合計(jì),商品刪除,商品數(shù)量加減等功能,這篇文章主要介紹了Android實(shí)現(xiàn)商城購(gòu)物車功能,需要的朋友可以參考下2019-06-06使用Thumbnails實(shí)現(xiàn)圖片指定大小壓縮
這篇文章主要為大家詳細(xì)介紹了使用Thumbnails實(shí)現(xiàn)圖片指定大小壓縮,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08android 獲取手機(jī)中的所有圖片或某一目錄下的圖片方法
下面小編就為大家分享一篇android 獲取手機(jī)中的所有圖片或某一目錄下的圖片方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02Android實(shí)現(xiàn)完整游戲循環(huán)的方法
這篇文章主要介紹了Android實(shí)現(xiàn)完整游戲循環(huán)的方法,以實(shí)例代碼形式較為詳細(xì)的分析了Android游戲循環(huán)的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10