IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android原生整合虹软SDK开发uniapp插件 -> 正文阅读

[移动开发]Android原生整合虹软SDK开发uniapp插件

1、项目背景

应公司要求,需要开发一套类似人脸打卡功能的app,但是因为我们公司没有很强的原生android开发者,所以根据现状选择了第三方跨平台的uniapp,想必目前大多人都了解这个平台了,我也就不多赘述了,直接上uniapp官方网站,它有一个缺点就是很多复杂的功能实现不了,就比如今天我们所要说的基于虹软开放平台的人脸识别功能,那么怎么办呢?当然有办法,使用android原生整合虹软SDK,然后做成插件供uniapp使用,这就是咱们今天的主题。另外具体虹软开放平台是做什么的,大家可以去官方做更深一步的了解,上官方链接:虹软官方,为什么要用虹软,多了不说,我就说一点:免费、免费、免费,这个理由怎么样?!以下是虹软开放平台提供的解决方案:
在这里插入图片描述

温馨提示

本篇就是针对小白写的,小白不用怕
另外也需要一定的android原生基础,入门能看懂代码即可,不需要精通

2、本篇用到的技术栈以及SDK

  • 虹软人脸识别SDK v3.0
  • android
  • vue
  • uniapp

3、技术接入部分

1、去虹软控制台(要登录哦)下载人脸识别Demo,传送阵,注意需要新建一个应用,如下图,SDK中包含Demo
在这里插入图片描述
2、 将Demo导入AndroidStudio,下图就是Demo的样子:
注意:AndroidStudio导入的项目路径一定不要有中文
在这里插入图片描述
3、如果不出意外的话,运行项目就会出现如下界面了,至此虹软Demo也就跑起来了
如果出意外了,请查看该文章的可能遇到的错误章节
在这里插入图片描述
4、接下来去跑uniapp的Demo,首先去uniapp官方下载Android平台uni原生插件开发Demo
5、将Demo导入AndroidStudio,下图就是Demo的样子:
注意:AndroidStudio导入的项目路径一定不要有中文
在这里插入图片描述
6、跑项目,会出现未配置appkey或配置错误字样,解决方法请参考:如何申请appkey传送阵
注意解决这个问题还是稍微比较复杂点的,请认真阅读官方文档,不要怀疑官方文档的正确性

//过程中需要用到的一个生成 sha1 值得命令,在 C:\Program Files\Java\jre1.8.0_291\bin 路径下运行 cmd
keytool.exe -list -v -keystore 【keystore文件的绝对路径】

7、拿到 appkey 之后,写入 AndroidManifest.xml 文件中的 meta-data 中,然后将申请 appkey 过程中申请的证书配置到项目中,再次跑项目,如果不出意外的话,运行项目就会出现如下界面了,至此uniapp的Demo也就跑起来了
在这里插入图片描述
8、两个 Demo 都跑起来了,接下来就是整合两个 Demo 了,首先在 uniapp 的 Demo 中右击创建一个Module
在这里插入图片描述
9、选择 Android Library ,在右侧填写如下图几个属性,注意 Package name 尽量与虹软Demo中的一致,因为之后会避免解决一些不必要的错误,下一步
在这里插入图片描述
10、将虹软 Demo 中的如下 文件夹中的所有内容(包括文件夹)复制到刚才创建的 Module 中的同样位置

libs
java
jniLibs
res

11、将 Module 中的 build.gradle 中的 dependencies 全部删除,加入下面的

implementation fileTree(dir: 'libs', include: ['*.jar'])
compileOnly fileTree(dir: '../app/libs', include: ['uniapp-v8-release.aar'])
implementation 'com.alibaba:fastjson:1.1.46.android'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.6'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
compileOnly "com.android.support:recyclerview-v7:28.0.0"
compileOnly "com.android.support:support-v4:28.0.0"
compileOnly "com.android.support:appcompat-v7:28.0.0"
implementation 'com.android.support.constraint:constraint-layout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

12、截至目前步骤,我们所有的准备基本已经就绪,接下来我们需要创建一下三个文件

FaceReco_AppProxy.java //用于初始化动态链接库
FaceReco.java //用于激活虹软SDK
FaceRecoView.java //用于人脸检测视图

在这里插入图片描述
13、我们找到 FaceAttrPreviewActivity 文件,将关于人脸识别的核心代码拷贝到 FaceRecoView 文件中,核心代码如下:

/**
 * 初始化引擎
 */
private void initEngine() {
    faceEngine = new FaceEngine();
    afCode = faceEngine.init(getContext(), DetectMode.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(getContext()),
            16, 20, FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_AGE | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_GENDER | FaceEngine.ASF_LIVENESS);
    Log.i(TAG, "initEngine:  init: " + afCode);
    if (afCode != ErrorInfo.MOK) {
        System.out.println(R.string.init_failed+":"+afCode);
    }
}

/**
 * 卸载引擎
 */
private void unInitEngine() {
    if (afCode == 0) {
        afCode = faceEngine.unInit();
        Log.i(TAG, "unInitEngine: " + afCode);
    }
}

/**
 * 初始化摄像头
 */
private void initCamera() {
    DisplayMetrics metrics = new DisplayMetrics();
    Activity activity = (Activity)getContext();
    activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    CameraListener cameraListener = new CameraListener() {

        @Override
        public void onCameraOpened(Camera camera, int cameraId, int displayOrientation, boolean isMirror) {
            Log.i(TAG, "onCameraOpened: " + cameraId + "  " + displayOrientation + " " + isMirror);
            previewSize = camera.getParameters().getPreviewSize();
            drawHelper = new DrawHelper(previewSize.width, previewSize.height, previewView.getWidth(), previewView.getHeight(), displayOrientation
                    , cameraId, isMirror, false, false);
        }

        @Override
        public void onPreview(byte[] nv21, Camera camera) {
            if (faceRectView != null) {
                faceRectView.clearFaceInfo();
            }
            List<FaceInfo> faceInfoList = new ArrayList<>();
            long start = System.currentTimeMillis();
            int code = faceEngine.detectFaces(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList);
            if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {
                code = faceEngine.process(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList, processMask);
                if (code != ErrorInfo.MOK) {
                    return;
                }
            } else {
                return;
            }
            List<AgeInfo> ageInfoList = new ArrayList<>();
            List<GenderInfo> genderInfoList = new ArrayList<>();
            List<Face3DAngle> face3DAngleList = new ArrayList<>();
            List<LivenessInfo> faceLivenessInfoList = new ArrayList<>();
            int ageCode = faceEngine.getAge(ageInfoList);
            int genderCode = faceEngine.getGender(genderInfoList);
            int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList);
            int livenessCode = faceEngine.getLiveness(faceLivenessInfoList);
            // 有其中一个的错误码不为ErrorInfo.MOK,return
            if ((ageCode | genderCode | face3DAngleCode | livenessCode) != ErrorInfo.MOK) {
                return;
            }
            System.out.println("检测成功");
            if (faceRectView != null && drawHelper != null) {
                List<DrawInfo> drawInfoList = new ArrayList<>();
                for (int i = 0; i < faceInfoList.size(); i++) {
                    drawInfoList.add(new DrawInfo(drawHelper.adjustRect(faceInfoList.get(i).getRect()), genderInfoList.get(i).getGender(), ageInfoList.get(i).getAge(), faceLivenessInfoList.get(i).getLiveness(), RecognizeColor.COLOR_UNKNOWN, null));
                }
                drawHelper.draw(faceRectView, drawInfoList);
            }
        }

        @Override
        public void onCameraClosed() {
            Log.i(TAG, "onCameraClosed: ");
        }

        @Override
        public void onCameraError(Exception e) {
            Log.i(TAG, "onCameraError: " + e.getMessage());
        }

        @Override
        public void onCameraConfigurationChanged(int cameraID, int displayOrientation) {
            if (drawHelper != null) {
                drawHelper.setCameraDisplayOrientation(displayOrientation);
            }
            Log.i(TAG, "onCameraConfigurationChanged: " + cameraID + "  " + displayOrientation);
        }
    };
    cameraHelper = new CameraHelper.Builder()
            .previewViewSize(new Point(previewView.getMeasuredWidth(), previewView.getMeasuredHeight()))
            .rotation(activity.getWindowManager().getDefaultDisplay().getRotation())
            .specificCameraId(rgbCameraId != null ? rgbCameraId : Camera.CameraInfo.CAMERA_FACING_FRONT)
            .isMirror(false)
            .previewOn(previewView)
            .cameraListener(cameraListener)
            .build();
    cameraHelper.init();
    cameraHelper.start();
}

14、此时人脸检测页面就整合到 uniapp 中了,当然还不可以使用,为什么呢?当然是还有两个文件没做完呢,一个用于激活SDK的,一个用于初始化加载动态链接库文件的,最重要的两步,开搞~
15、首先将初始化动态链接库文件代码写入 FaceReco_AppProxy 文件中

/**
 * 检查能否找到动态链接库,如果找不到,请修改工程配置
 *
 * @param libraries 需要的动态链接库
 * @return 动态库是否存在
 */
private boolean checkSoFile(String[] libraries,Application application) {
    ApplicationInfo applicationInfo = application.getApplicationInfo();
    File dir = new File(applicationInfo.nativeLibraryDir);
    System.out.println("文件路径:"+dir.getAbsolutePath());
    File[] files = dir.listFiles();
    if (files == null || files.length == 0) {
        return false;
    }
    List<String> libraryNameList = new ArrayList<>();
    for (File file : files) {
        System.out.println("文件名字:"+file.getName());
        libraryNameList.add(file.getName());
    }
    boolean exists = true;
    for (String library : libraries) {
        exists &= libraryNameList.contains(library);
    }
    return exists;
}

16、然后激活SDK文件代码写入 FaceReco 文件中

/**
 * 激活设备
 */
private void active(){
    Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) {
            RuntimeABI runtimeABI = FaceEngine.getRuntimeABI();
            Log.i(TAG, "subscribe: getRuntimeABI() " + runtimeABI);
            int activeCode = FaceEngine.activeOnline(mUniSDKInstance.getContext(), CommonUtil.getAppId(), CommonUtil.getSdkKey());
            emitter.onNext(activeCode);
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<Integer>() {
                @Override
                public void onSubscribe(Disposable d) {

                }
                @Override
                public void onNext(Integer activeCode) {
                    if (activeCode == ErrorInfo.MOK) {
                        showToast(getString(R.string.active_success));
                        mJsCallback.invokeAndKeepAlive("激活成功");
                    } else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) {
                        showToast(getString(R.string.already_activated));
                        mJsCallback.invokeAndKeepAlive("该设备已激活");
                    } else {
                        showToast(getString(R.string.active_failed)+":"+activeCode);
                        mJsCallback.invokeAndKeepAlive("激活失败,错误码:"+activeCode);
                    }
                    ActiveFileInfo activeFileInfo = new ActiveFileInfo();
                    int res = FaceEngine.getActiveFileInfo(mUniSDKInstance.getContext(), activeFileInfo);
                    if (res == ErrorInfo.MOK) {
                        Log.i(TAG, activeFileInfo.toString());
                    }
                }
                @Override
                public void onError(Throwable e) {
                    showToast(e.getMessage());
                }
                @Override
                public void onComplete() {

                }
            });
}

17、将 AndroidManifest.xml 文件替换如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.arcsoft.arcfacedemo">

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

</manifest>

18、至此,咱们插件的所有的配置基本完成,接下来删除两个文件夹,为什么要删除这两个文件夹呢,因为这两个文件夹都是安卓原生的 activity 视图,因为目前咱们的视图是 uniapp 来驱动的,所以用不到这些东西了

activity
fragment

19、将 app 项目中引入咱们的插件,在 app 项目中的 build.gradle 中配置

implementation project(':arcfacedemo')

20、将项目跑起来,没有任何错误,漂亮,一切皆是那么的完美,如下图,呵呵,没有任何变化,为什么没有变化呢?咱们继续
在这里插入图片描述
21、刚刚看到的是咱们的 uniapp 主界面,咱们目前只是把插件部分做完了,接下来就是让 uniapp 去调咱们的插件,首先去写一个界面,在这里我就不写界面了,我就直接说怎么调插件了,咦,对了,咱们的插件还没有打包,接下来打包插件
22、在 Android Studio 中选择 Build->Rebuild Project ,就将插件打包好了,如图:
在这里插入图片描述
23、怎么用呢?在这里我提供一下 package.json ,有了这个就不用我多说了吧!

{
    "name": "虹软SDK人脸检测",
    "id": "arc-face",
    "version": "1.0.0",
    "description": "基于虹软SDK开发的人脸检测插件,插件永久维护,欢迎提需求(qq群:785919513)",
    "_dp_type":"nativeplugin",
    "_dp_nativeplugin":{
        "android": {
            "plugins": [
            	{
					"type": "module",
					"name": "arc-faceReco",
					"class": "com.arcsoft.arcfacedemo.FaceReco"
				},
				{
					"type": "component",
					"name": "arc-faceRecoView",
					"class": "com.arcsoft.arcfacedemo.FaceRecoView"
				}
            ],
            "hooksClass": "com.arcsoft.arcfacedemo.FaceReco_AppProxy",
            "integrateType": "aar",
            "abis": [
                "armeabi-v7a",
                "arm64-v8a"
            ],
            "minSdkVersion":23
        }
    }
}

24、至此插件制作的全过程讲解完毕

4、可能遇到的错误

这个怎么说呢!一般遇到编译不通过的错误大部分都是环境问题,或者业务问题,这个需要对症下药,博主说一下自己在整合的时候遇到的一些问题吧

  1. 找不到动态链接库(.so文件)
    解决方法:忘记把 .so 文件拷贝过来
  2. 忘记这个错误了,稍后补上
    解决方法:创建 Module 时选择 Android Library ,而不是选择 Phone & Tablet

5、完结

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 11:35:50  更:2021-07-10 11:35:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 7:01:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码