贾志浩 發表於 2021-8-5 11:37:00

《Android原生整合虹软SDK开发uniapp插件》

<hr>
<h1 id="1项目背景">1、项目背景</h1>
<p><strong>1.应公司要求,需要开发一套类似人脸打卡功能的app,但是因为我们公司没有很强的原生android开发者,所以根据现状选择了第三方跨平台的uniapp,想必目前大多人都了解这个平台了,我也就不多赘述了,直接上uniapp官方网站,它有一个缺点就是很多复杂的功能实现不了,就比如今天我们所要说的基于虹软开放平台的人脸识别功能,那么怎么办呢?当然有办法,使用android原生整合虹软SDK,然后做成插件供uniapp使用,这就是咱们今天的主题。另外具体虹软开放平台是做什么的,大家可以去官方做更深一步的了解,上官方链接:虹软官方,为什么要用虹软,多了不说,我就说一点:免费、免费、免费,这个理由怎么样?!以下是虹软开放平台提供的解决方案:</strong></p>
<p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a45278a4848844d3a6b60385f0892476~tplv-k3u1fbpfcp-watermark.image"></p>
<p><font color="red"><strong>温馨提示</strong></font></p><font color="red">
<p><strong>本篇就是针对小白写的,小白不用怕</strong></p>
</font><p><font color="red"><strong>另外也需要一定的android原生基础,入门能看懂代码即可,不需要精通</strong></font></p>
<h1 id="2本篇用到的技术栈以及sdk">2、本篇用到的技术栈以及SDK</h1>
<h1 id="_"></h1>
<h4 id="----虹软人脸识别sdk-v30">-   虹软人脸识别SDK v3.0</h4>
<h4 id="----android">-   android</h4>
<h4 id="----vue">-   vue</h4>
<h4 id="----uniapp">-   uniapp</h4>
<h1 id="3技术接入部分">3、技术接入部分</h1>
<h4 id="1去虹软控制台要登录哦下载人脸识别demo传送阵">1、去虹软控制台(要登录哦)下载人脸识别Demo,传送阵,</h4>
<h4 id="注意需要新建一个应用如下图sdk中包含demo">注意需要新建一个应用,如下图,SDK中包含Demo</h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2d05b1d74afc4a999c4119f0614fc56f~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="2-将demo导入androidstudio下图就是demo的样子">2、 将Demo导入AndroidStudio,下图就是Demo的样子:</h4>
<h4 id="_-1"></h4>
<p>$\color{DarkTurquoise}{注意:AndroidStudio导入的项目路径一定不要有中文}$</p>
<p>*<img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7277a6b7a88c4123befdf5c665331daf~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="3如果不出意外的话运行项目就会出现如下界面了至此虹软demo也就跑起来了">3、如果不出意外的话,运行项目就会出现如下界面了,至此虹软Demo也就跑起来了</h4>
<h5 id="如果出意外了请查看该文章的colordarkturquoise可能遇到的错误章节">如果出意外了,请查看该文章的$\color{DarkTurquoise}{可能遇到的错误}$章节</h5>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f953e0f80acb451f8aba75b9852d6416~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="4接下来去跑uniapp的demo首先去uniapp官方下载android平台uni原生插件开发demo">4、接下来去跑uniapp的Demo,首先去uniapp官方下载Android平台uni原生插件开发Demo</h4>
<h4 id="5将demo导入androidstudio下图就是demo的样子">5、将Demo导入AndroidStudio,下图就是Demo的样子:</h4>
<h4 id="_-2"></h4>
<p>$\color{DarkTurquoise}{注意:AndroidStudio导入的项目路径一定不要有中文}$</p>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4b9194d5bb1149c69d180bfe8031cf31~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="6跑项目会出现colordarkturquoise未配置appkey或配置错误字样解决方法请参考如何申请appkey传送阵">6、跑项目,会出现$\color{DarkTurquoise}{未配置appkey或配置错误}$字样,解决方法请参考:如何申请appkey传送阵\</h4>
<h4 id="colordarkturquoise注意解决这个问题还是稍微比较复杂点的请认真阅读官方文档不要怀疑官方文档的正确性">$\color{DarkTurquoise}{注意解决这个问题还是稍微比较复杂点的,请认真阅读官方文档,不要怀疑官方文档的正确性}$</h4>
<pre><code>
//过程中需要用到的一个生成 sha1 值得命令,在 C:\Program Files\Java\jre1.8.0_291\bin 路径下运行 cmd
keytool.exe -list -v -keystore 【keystore文件的绝对路径】

</code></pre>
<h4 id="7拿到-appkey-之后写入-androidmanifestxml-文件中的-meta-data-中然后将申请-appkey-过程中申请的证书配置到项目中再次跑项目如果不出意外的话运行项目就会出现如下界面了至此uniapp的demo也就跑起来了">7、拿到 appkey 之后,写入 AndroidManifest.xml 文件中的 meta-data 中,然后将申请 appkey 过程中申请的证书配置到项目中,再次跑项目,如果不出意外的话,运行项目就会出现如下界面了,至此uniapp的Demo也就跑起来了</h4>
<h4 id="_-3"></h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/98bc78f6a18143e994cad52c0b3800ef~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="8两个-demo-都跑起来了接下来就是整合两个-demo-了首先在-uniapp-的-demo-中右击创建一个module">8、两个 Demo 都跑起来了,接下来就是整合两个 Demo 了,首先在 uniapp 的 Demo 中右击创建一个Module</h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/68ec9c22dd194c758ddacf599d17dae3~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="9选择-android-library-在右侧填写如下图几个属性注意-package-name-尽量与虹软demo中的一致因为之后会避免解决一些不必要的错误下一步">9、选择 Android Library ,在右侧填写如下图几个属性,注意 Package name 尽量与虹软Demo中的一致,因为之后会避免解决一些不必要的错误,下一步</h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1295ea22f229436fa4da0092aec10118~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="10将虹软-demo-中的如下-文件夹中的所有内容包括文件夹复制到刚才创建的-module-中的同样位置">10、将虹软 Demo 中的如下 文件夹中的所有内容(包括文件夹)复制到刚才创建的 Module 中的同样位置</h4>
<pre><code>libs
java
jniLibs
res
</code></pre>
<h4 id="11将-module-中的-buildgradle-中的-dependencies-全部删除加入下面的">11、将 Module 中的 build.gradle 中的 dependencies 全部删除,加入下面的</h4>
<pre><code class="language-implementation">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'

</code></pre>
<h4 id="12截至目前步骤我们所有的准备基本已经就绪接下来我们需要创建一下三个文件">12、截至目前步骤,我们所有的准备基本已经就绪,接下来我们需要创建一下三个文件</h4>
<pre><code class="language-js">FaceReco_AppProxy.java //用于初始化动态链接库
FaceReco.java //用于激活虹软SDK
FaceRecoView.java //用于人脸检测视图
</code></pre>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0461e27b0fc34ae9a6556df2156d8783~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="13我们找到-faceattrpreviewactivity-文件将关于人脸识别的核心代码拷贝到-facerecoview-文件中核心代码如下">13、我们找到 FaceAttrPreviewActivity 文件,将关于人脸识别的核心代码拷贝到 FaceRecoView 文件中,核心代码如下:</h4>
<h4 id="_-4"></h4>
<pre><code class="language-/**"> * 初始化引擎
*/
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&lt;FaceInfo&gt; faceInfoList = new ArrayList&lt;&gt;();
            long start = System.currentTimeMillis();
            int code = faceEngine.detectFaces(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList);
            if (code == ErrorInfo.MOK &amp;&amp; faceInfoList.size() &gt; 0) {
                code = faceEngine.process(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList, processMask);
                if (code != ErrorInfo.MOK) {
                  return;
                }
            } else {
                return;
            }
            List&lt;AgeInfo&gt; ageInfoList = new ArrayList&lt;&gt;();
            List&lt;GenderInfo&gt; genderInfoList = new ArrayList&lt;&gt;();
            List&lt;Face3DAngle&gt; face3DAngleList = new ArrayList&lt;&gt;();
            List&lt;LivenessInfo&gt; faceLivenessInfoList = new ArrayList&lt;&gt;();
            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 &amp;&amp; drawHelper != null) {
                List&lt;DrawInfo&gt; drawInfoList = new ArrayList&lt;&gt;();
                for (int i = 0; i &lt; 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();
}

</code></pre>
<h4 id="14此时人脸检测页面就整合到-uniapp-中了当然还不可以使用为什么呢当然是还有两个文件没做完呢一个用于激活sdk的一个用于初始化加载动态链接库文件的最重要的两步开搞">14、此时人脸检测页面就整合到 uniapp 中了,当然还不可以使用,为什么呢?当然是还有两个文件没做完呢,一个用于激活SDK的,一个用于初始化加载动态链接库文件的,最重要的两步,开搞~\</h4>
<h4 id="15首先将初始化动态链接库文件代码写入-facereco_appproxy-文件中">15、首先将初始化动态链接库文件代码写入 FaceReco_AppProxy 文件中</h4>
<pre><code class="language-/**"> * 检查能否找到动态链接库,如果找不到,请修改工程配置
*
* @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&lt;String&gt; libraryNameList = new ArrayList&lt;&gt;();
    for (File file : files) {
      System.out.println("文件名字:"+file.getName());
      libraryNameList.add(file.getName());
    }
    boolean exists = true;
    for (String library : libraries) {
      exists &amp;= libraryNameList.contains(library);
    }
    return exists;
}


</code></pre>
<h4 id="16然后激活sdk文件代码写入-facereco-文件中">16、然后激活SDK文件代码写入 FaceReco 文件中</h4>
<h4 id="_-5"></h4>
<pre><code>/**
* 激活设备
*/
private void active(){
    Observable.create(new ObservableOnSubscribe&lt;Integer&gt;() {
      @Override
      public void subscribe(ObservableEmitter&lt;Integer&gt; 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&lt;Integer&gt;() {
                @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() {

                }
            });
}

</code></pre>
<h4 id="17将-androidmanifestxml-文件替换如下">17、将 AndroidManifest.xml 文件替换如下:</h4>
<h4 id="_-6"></h4>
<pre><code class="language-&lt;?xml">&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.arcsoft.arcfacedemo"&gt;

    &lt;uses-permission android:name="android.permission.CAMERA" /&gt;
    &lt;uses-permission android:name="android.permission.READ_PHONE_STATE" /&gt;
    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
    &lt;uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /&gt;
    &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
    &lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;

&lt;/manifest&gt;

</code></pre>
<h4 id="18至此咱们插件的所有的配置基本完成接下来删除两个文件夹为什么要删除这两个文件夹呢因为这两个文件夹都是安卓原生的-activity-视图因为目前咱们的视图是-uniapp-来驱动的所以用不到这些东西了">18、至此,咱们插件的所有的配置基本完成,接下来删除两个文件夹,为什么要删除这两个文件夹呢,因为这两个文件夹都是安卓原生的 activity 视图,因为目前咱们的视图是 uniapp 来驱动的,所以用不到这些东西了</h4>
<pre><code>activity
fragment
</code></pre>
<h4 id="19将-app-项目中引入咱们的插件在-app-项目中的-buildgradle-中配置">19、将 app 项目中引入咱们的插件,在 app 项目中的 build.gradle 中配置</h4>
<h4 id="_-7"></h4>
<pre><code>implementation project(':arcfacedemo')
</code></pre>
<h4 id="20将项目跑起来没有任何错误漂亮一切皆是那么的完美如下图呵呵没有任何变化为什么没有变化呢咱们继续">20、将项目跑起来,没有任何错误,漂亮,一切皆是那么的完美,如下图,呵呵,没有任何变化,为什么没有变化呢?咱们继续!</h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c2b55ad8906d4888bf90a349e2e8ed1e~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="21刚刚看到的是咱们的-uniapp-主界面咱们目前只是把插件部分做完了接下来就是让-uniapp-去调咱们的插件首先去写一个界面在这里我就不写界面了我就直接说怎么调插件了咦对了咱们的插件还没有打包接下来打包插件">21、刚刚看到的是咱们的 uniapp 主界面,咱们目前只是把插件部分做完了,接下来就是让 uniapp 去调咱们的插件,首先去写一个界面,在这里我就不写界面了,我就直接说怎么调插件了,咦,对了,咱们的插件还没有打包,接下来打包插件</h4>
<h4 id="_-8"></h4>
<h4 id="22在-android-studio-中选择-build-rebuild-project-就将插件打包好了如图">22、在 Android Studio 中选择 Build-&gt;Rebuild Project ,就将插件打包好了,如图:</h4>
<h4 id="_-9"></h4>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1ff648536224b339bffcc420f52a0e8~tplv-k3u1fbpfcp-zoom-1.image"></p>
<h4 id="23怎么用呢在这里我提供一下-packagejson-有了这个就不用我多说了吧">23、怎么用呢?在这里我提供一下 package.json ,有了这个就不用我多说了吧!</h4>
<h4 id="_-10"></h4>
<pre><code>{
    "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
      }
    }
}

</code></pre>
<h4 id="24至此插件制作的全过程讲解完毕">24、至此插件制作的全过程讲解完毕\</h4>
<h4 id="25最后附上源码源码传送阵">25、最后附上源码:源码传送阵</h4>
<h1 id="4可能遇到的错误">4、可能遇到的错误</h1>
<h4 id="这个怎么说呢一般遇到编译不通过的错误大部分都是环境问题或者业务问题这个需要对症下药博主说一下自己在整合的时候遇到的一些问题吧">这个怎么说呢!一般遇到编译不通过的错误大部分都是环境问题,或者业务问题,这个需要对症下药,博主说一下自己在整合的时候遇到的一些问题吧</h4>
<h4 id="_-11"></h4>
<h4 id="1找不到动态链接库so文件">1.找不到动态链接库(.so文件)</h4>
<h4 id="解决方法忘记把-so-文件拷贝过来">解决方法:忘记把 .so 文件拷贝过来</h4>
<h4 id="_-12"></h4>
<h4 id="2忘记这个错误了稍后补上">2.忘记这个错误了,稍后补上</h4>
<h4 id="解决方法创建-module-时选择-android-library-而不是选择-phone--tablet">解决方法:创建 Module 时选择 Android Library ,而不是选择 Phone &amp; Tablet</h4>
<h4 id="_-13"></h4>
<h4 id="3忘记这个错误了稍后补上">3.忘记这个错误了,稍后补上</h4>
<h4 id="解决方法项目路径中不要有中文">解决方法:项目路径中不要有中文</h4>
<h1 id="5完结">5、完结</h1>
<h4 id="了解更多人脸识别产品相关内容请到虹软视觉开放平台哦"><strong>了解更多人脸识别产品相关内容请到虹软视觉开放平台哦</strong></h4><br><br>
来源:https://www.cnblogs.com/ccLqqy/p/15102597.html
頁: [1]
查看完整版本: 《Android原生整合虹软SDK开发uniapp插件》