Android OCR UI 自定义说明

更新时间:
复制为 MD 格式

金融级实人认证产品方案中OCR功能的内容页和拍照页可以通过重写Fragment实现接口的方式自定义UI。

概述

金融级实人认证方案中有包含OCR功能的产品,其中OCR功能的内容页(Content)拍照页(TakePhoto)可以通过以下两种方式进行自定义:

  • 修改部分UI:继承SDK中的OCRFragment(OCRContentFragment/OCRTakePhotoFragment),重写方法。

  • 完全自定义UI:实现SDK中的IDTOCRFragment(IDTOCRContentFragment/IDTOCRTakePhotoFragment)接口。

重要

部分自定义配置可能需要依赖SDK升级,建议您在使用之前将SDK升级至最新版本

生效方式

假设自定义UI的类名为:CustomOCRContentFragmentCustomOCRTakePhotoFragment,参考以下代码使自定义UI生效:

//CustomOCRContentFragment为自定义OCR信息页,需要实现IDTOCRContentFragment接口
DTFOcrFacade.setOCRContentFragment(CustomOCRContentFragment.class);

//设置OCR拍照页Fragment
//CustomOCRTakePhotoFragment为自定义拍照页,需要实现IDTOCRTakePhotoFragment接口
DTFOcrFacade.setOCRTakePhotoFragment(CustomOCRTakePhotoFragment.class);

通过继承SDK中的类部分自定义UI

SDK中提供了OCRContentFragmentOCRTakePhotoFragment两个Fragment,可以通过继承重写的方式来实现对OCR内容页拍照页UI自定义。

  • UI定制:通过修改布局文件实现。

    重写 getLayoutID 方法,返回自己的布局文件。

    建议从R.layout.dtf_fragment_ocr_content/R.layout.fragment_ocr_take_photo中复制出来进行修改,控件id不要修改。

    复制方法可参考下图:

    image

  • 文案及事件定制:通过公开的获取页面控件的方法拿到控件进行自定义设置。

继承重写示例

CustomSimpleOCRContentFragment.java

public class CustomSimpleOCRContentFragment extends OCRContentFragment {

    //自定义的进度条布局,需要实现IGuideStageView接口
    private CustomStageView customStageView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        customStageView = (CustomStageView) getStageView();
        IGuideStageView guideStageView = (IGuideStageView) customStageView;
        if (null != guideStageView) {
            customStageView.setTitle("继承模式: 当前进度");
        }

        View viewTitle = getTitleView();
        if (viewTitle instanceof ITitleView) {
            ITitleView titleView = (ITitleView) viewTitle;
            titleView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //todo:返回按钮点击
                }
            });
        }
        //...
        return mRootView;
    }

    //获取进度条控件
    @Override
    public View getStageView() {
        customStageView = findViewById(R.id.view_stage);
        return customStageView;
    }

    /**
     * 获取title布局
     * */
    @Override
    public View getTitleView() {
        return super.getTitleView();
    }

    /**
    * 获取身份证点击区域布局
    * */
    @Override
    public View getCardPhotoView() {
        return super.getCardPhotoView();
    }

    /**
     * 获取身份证识别信息显示布局
     * */
    @Override
    public View getInfoView() {
        return super.getInfoView();
    }

    /**
     * 获取底部button所在布局
     * */
    @Override
    public View getBottomBtnView() {
        return super.getBottomBtnView();
    }


    @Override
    public int getLayoutID() {
        //将SDK中的R.layout.dtf_fragment_ocr_content内容复制出来,对需要调整的部分样式进行调整,控件id不可修改;
        return R.layout.custom_simple_fragment_ocr_content;
    }


    //在弹框显示回调中,实现自定义弹框
    @Override
    public boolean onMessageBoxShow(String title, String message, String passTip, String cancelTip, String errCode, IDTUICallBack.MessageBoxCallBack messageBoxCallBack) {
        AlertDialog.Builder builder = new AlertDialog.Builder(mRootView.getContext());
        builder.setTitle(title)
        .setMessage(message)
        .setPositiveButton(passTip, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                messageBoxCallBack.onOK();
            }
        }).setNegativeButton(cancelTip, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.show();
        return true;
    }
}

CustomSimpleOCRTakePhotoFragment.java

public class CustomSimpleOCRTakePhotoFragment extends OCRTakePhotoFragment{

    @Override
    public int getLayoutID() {
        return R.layout.custom_fragment_ocr_take_photo;
    }

    /**
     * 设置拍照框顶部的文案
     * */
    public void setTakePhotoTips() {
        TextView textViewFrameTips = findViewById(R.id.ocr_take_photo_rect_frame_tips);
        if (null != textViewFrameTips) {
            textViewFrameTips.setTextColor(getResources().getColor(R.color.dtf_ocr_white));

            if (isFront()) {
                textViewFrameTips.setText("拍摄身份证人像面(继承)");
            } else {
                textViewFrameTips.setText("拍摄身份证国徽面(继承)");
            }
        }
    }

}

通过实现SDK中的接口完全自定义UI

通过实现接口的方式可完全自主实现OCR内容页拍照页UI。

OCR内容页

创建自定义信息页Fragment,实现com.dtf.face.ocr.api.IDTOCRContentFragment接口。

接口定义

public interface IDTOCRContentFragment extends IDTBaseOCRUICallBack {

    /**
     * 权限获取到时
     * */
    void onPermissionGranted();

    /**
     * 注入回调,用于调用SDK方法
     * */
    void setOCRCallback(IOCRCallback iocrCallback);

    /**
     * 拍照完成
     *@params rectF 剪裁框
     */
    void onPhotoTakenCompleted(Bitmap bitmap, RectF rectF);

    /***
     * 认证结果返回
     * */
    void onIdentityResult(OCRInfo ocrInfo, ErrorModel errorModel);

    /**
     * 显示loading
     */
    void showLoading();

    /**
     * 隐藏loading
     * */
    void hideLoading();

    /**
     * 关闭拍照页面
     */
    void finishTakePhotoPage();

    /**
     * 标题栏
     * */
    interface ITitleView {
        void setOnClickListener(View.OnClickListener onClickListener);
    }

    /**
     * 进度条
     * */
    interface IGuideStageView {
        /**
         * 设置当前进度
         * */
        void setStage(OCRConst.OCRStage stage);
    }

    /**
     * 图片显示区域
     * */
    interface ICardPhotoView {

        /**
         * 设置显示的图片
         * @param isFront 是身份证正面
         * @param roiImage 图片,为null时切换为默认图片
         * */
        void setCardPhoto(boolean isFront, Bitmap roiImage);

        interface IClickListener {
            /**
             * 点击"拍照要求",用于显示"拍照要求"弹框
             * */
            void onRequireClick();

            /**
             * 身份证图片点击
             * */
            void onCardClick();
        }

        void setOnClickListener(IClickListener iClickListener);
    }

    /**
     * OCR结果显示区域
     * */
    interface IInfoView {
        /**
         * 设置识别到的身份信息到UI
         * */
        void setInfo(String certName, String certNo);

        /**
         * 从UI获取姓名/身份证号用于后续认证
         * */
        OCRInfo getInfo();
    }

    interface IBottomBtnView {

        void setOnClickListener(View.OnClickListener onClickListener);

        /**
         * 设置btn文案及可用性
         */
        void setTxtAndEnable(String txt, boolean enable);
    }

}

其中注入的回调 com.dtf.face.ocr.api.IOCRCallback 方法,用于对SDK中的方法进行调用。

IOCRCallback定义:

public interface IOCRCallback {
    /**
     * 检查权限
     * @return 权限已获取
     */
    boolean checkPermission();
    
    /**
     * 发起识别
     * */
    void startOCRIdentify(Bitmap bitmap);
    
    /**
     * 校验、更新OCR信息
     * @return OCR_INFO_VALID.校验通过 OCR_CERT_NO_INVALID.身份证校验不过 OCRConst.OCR_CERT_NAME_INVALID.姓名校验不过
     * */
    String updateOcrInfo(OCRInfo ocrInfo);
    
    /**
     * 获取当前进度
     * */
    OCRConst.OCRStage getCurrentStage();
    
    /**
     * 切换下一进度
     * @param errorModel 切换进度异常时的错误信息
     * @return 切换后的进度
     * */
    OCRConst.OCRStage nextStage(ErrorModel errorModel);
    
    /**
     * 主动退出认证
     * */
    void onExit();
    
    /**
     * 拍照页面关闭点击
     * */
    void onTakePhotoCloseClick();
    
    /**
     * 获取拍照presenter,打开拍照fragment时需要给presenter设置IOCRCallback
     * */
    ITakePhotoPresenter getOCRTakePhotoPresenter();
    
    /**
     * 错误退出
     * */
    void onError(String code);
}

调用方式

发起识别

调用startOCRIdentify方法,传入图片进行识别。

// 注意iOCRCallback应该替换为实际实现类或其实例。
iOCRCallback.startOCRIdentify(bitmapCrop);

识别结果处理

通过实现IDTOCRContentFragment接口中onIdentityResult(OCRInfo ocrInfo, ErrorModel errorModel)方法来处理对识别结果的展示。

  • OCRInfo为识别到的卡片信息,识别失败该字段返回null;

    OCRInfo定义

    public class OCRInfo {
        //姓名
        public String name;
        //证件号码
        public String num;
        //有效期开始日期,格式YYYYMMDD
        public String startDate;
        //有效期结束日期,格式YYYYMMDD
        public String endDate;
        //当前是否为正面信息
        public boolean isFront = true;
    }
  • ErrorModel是对结果的描述,其errCode属性返回1000(OCRConst.RECOGNIZED_SUCCESS)时表示识别成功。

    ErrorModel定义

    public class ErrorModel {
    
        public ErrorModel() {
        }
    
        public ErrorModel(String errCode) {
            this.errCode = errCode;
        }
        //弹框信息
        public String title;
        public String message;
        public String passTip;
        public String cancelTip;
        public String errCode;
        public IDTUICallBack.MessageBoxCallBack messageBoxCallBack;
    }
@Override
public void onIdentityResult(OCRInfo ocrInfo, ErrorModel errorModel) {
    if (null == errorModel || OCRConst.RECOGNIZED_SUCCESS.equals(errorModel.errCode)) {
        //成功
    } else {
        //失败
        if (ToygerConst.ZcodeConstants.ZCODE_OCR_IDENTITY_MAX_COUNT.equals(errorModel.errCode)) {
            //对于失败超过次数
        } else {
            //对于识别失败的处理
        }
    }
}

确认识别结果

修改识别错误的身份证号(OCRInfo.num)或姓名(OCRInfo.name)后,通过IOCRCallback调用updateOcrInfo方法保存证件信息到SDK,SDK对修改后的OCRInfo进行校验,格式不符合将返回异常原因,需要调整后重新调用,否则无法切换到下一步

    /**
     * 校验、更新OCR信息
     * @return OCR_INFO_VALID.校验通过 OCR_CERT_NO_INVALID.身份证校验不过 OCRConst.OCR_CERT_NAME_INVALID.姓名校验不过
     * */
    String updateOcrInfo(OCRInfo ocrInfo);

updateOcrInfo方法返回值:

public class OCRConst {
    //校验通过
    public final static String OCR_INFO_VALID = "ocr_info_valid";
    //姓名非法
    public final static String OCR_CERT_NAME_INVALID = "ocr_cert_name_invalid";
    //证件号非法
    public final static String OCR_CERT_NO_INVALID = "ocr_cert_no_invalid";
}

切换到下一步

通过IOCRCallback调用nextStage方法切换SDK进度,传入ErrorModel以接收切换失败时的错误码。

/**
 * 切换下一进度
 * @param errorModel 切换进度异常时的错误信息
 * @return 切换后的进度
 * */
OCRConst.OCRStage nextStage(ErrorModel errorModel);

切换进度失败原因:

public class OCRConst {
    //正面信息未确认完成
    public final static String FRONT_NOT_COMPLETED = "front_not_completed";
    //反面信息未确认完成
    public final static String BACK_NOT_COMPLETED = "back_not_completed";
}

nextStage返回值,OCR进度枚举:

public class OCRConst {
    /**
     * OCR进度
     */
    public enum OCRStage {
        //身份证正面
        DTFOCRVerifyFront("DTFOCRVerifyFront"),
        //身份证反面
        DTFOCRVerifyBack("DTFOCRVerifyBack"),
        //即将跳转刷脸
        DTFOCRVerifyTransition("DTFOCRVerifyTransition");
        private final String name;

        OCRStage(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }
}

OCR拍照页

创建自定义信息页Fragment,实现com.dtf.face.ocr.api.IDTOCRContentFragment接口。

接口定义

public interface IDTOCRTakePhotoFragment extends IDTBaseOCRUICallBack {

    /**
     * 通过回调调用SDK方法
     */
    void setOCRCallback(ITakePhotoCallback iOCRCallback);

    /**
     * onSurfaceChanged调用时
     */
    void onSurfaceChanged(double previewWidth, double previewHeight);

    /**
     * 拍照完成,bitmap为拍好的图片
     */
    void setTakenPicture(Bitmap bitmap);

    /**
    *调用SDK方法
    */
    interface ITakePhotoCallback {

        /**
         * 切换闪光灯
         */
        boolean switchFlash(boolean open);

        /**
         * 拍照
         */
        void onClickTakePhoto();

        /**
         * 确认照片并返回
         *
         * @param takenPicture 采集的完整照片
         * @param rect         剪裁框
         */
        void onClickConfirmPhoto(Bitmap takenPicture, RectF rect);

        /**
         * 重新拍照
         **/
        void reTakePhoto();

        /**
         * 关闭
         */
        void onClickClose();

        /**
         * 获取预览view
         */
        SurfaceView getSurfaceView();

        /**
         * 获取当前进度
         */
        OCRConst.OCRStage getStage();

    }
}

调用方式

回调注入

调用IDTOCRTakePhotoFragmentsetOCRCallback(ITakePhotoCallback iOCRCallback)方法,注入iOCRCallback,通过iOCRCallback来调用SDK中的方法。

预览调整

实现IDTOCRTakePhotoFragmentonSurfaceChanged方法以调整布局。

相机图像预览

调用ITakePhotoCallbackgetSurfaceView方法,获取预览SurfaceView

切换闪光灯状态

调用ITakePhotoCallbackswitchFlash(boolean open)方法完成对闪光灯的打开(常亮)和关闭,opentrue表示打开闪光灯。

拍摄照片

调用ITakePhotoCallbackonClickTakePhoto()方法完成对图像的采集并停止摄像头实时预览。

照片预览

IDTOCRTakePhotoFragment接口的setTakenPicture(Bitmap bitmap)方法实现中,完成对拍摄照片步骤中采集照片的预览。

重新拍摄

调用ITakePhotoCallbackreTakePhoto()方法来恢复相机预览。

照片确认

调用ITakePhotoCallbackonClickConfirmPhoto(Bitmap takenPicture, RectF rect)方法完成对采集照片的确认并发起识别,takenPicture为采集的完整照片,rect为剪裁框。

关闭页面

调用ITakePhotoCallbackonClickClose方法关闭拍摄页面。

获取SDK当前进度:

调用ITakePhotoCallbackgetStage()方法,获取当前认证进度。