android 5.0设备 动态加载so文件

先说一下写这个的初衷,  公司做的项目是安卓设备5.0系统 最近需要集成人脸识别第三方.  犹豫环境特殊 需要做离线授权 也就是加载特定的授权离线SO 文件  由于 设备很多 避免多次打包APK 所以  通过 外部加载指定的SO文件来实现功能

 下面 是具体的代码 和流程  

    /**
     * 识别 动态调用so文件 注意事项及流程
     * 1、 获取so文件存放路径(sdcard/Download)然后复制到date/date下调用 存放路径可自己设置
     * 2、 FaceCheck.class 需要隐藏 System.loadLibrary("FaceCheck");
     * 3、 APP bulid 下需要添加向下兼容的NDK
     * 4、 提前删掉libs文件中的FaceCheck()
     * 5、 Android.mk  添加  TARGET_CPU_API := armeabi  APP_ABI := armeabi
     *
     */
    private void initdata() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    if (LoadSoFileUtils.loadSoFile(MainActivity.this, "/sdcard/Download")!=0){
                        Toast.makeText(MainActivity.this,"未检测到SO文件,请配置好重新启动APP",Toast.LENGTH_LONG).show();
                        logger.debug("未检测到SO文件,请配置好重新启动APP,离线授权so文件可联系开发人员");
                        return;
                    }
                    File dir = MainActivity.this.getDir("Lib", Context.MODE_PRIVATE);
                    System.load(dir.getAbsolutePath() + "/libFaceCheck.so");
                    logger.debug("so文件动态加载成功");
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.debug("so文件动态加载失败");
                }
                Message message = Message.obtain();
                message.what = SO_LOADING;
                mHandler.sendMessage(message);
            }
        });
    }

通常启用so文件  是使用System.loadLibrary  这个来通过调用 , 在此 我们复制完so文件后通过 System.load 来进行提前加载处理

package com.hongsen.outdoor.utils;

/**
 * 作者:Mio
 * 时间:2020/04/16.
 * 邮箱:17379235050@163.com
 * 描述:
 */

import android.content.Context;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * so库从sd卡拷贝到app的私有目录下,并进行比对验证和加载
 */

public class LoadSoFileUtils {
    private static String nameSO = "libFaceCheck";

    /**
     * 加载 so 文件
     */
    public static int loadSoFile(Context context, String fromPath) {
        File dir = context.getDir("Lib", Context.MODE_PRIVATE);
        String fromPathFile = fromPath + "/" + nameSO + ".so";
        File isExist = new File(fromPathFile);
        if (!isLoadSoFile(dir, isExist.exists())) {
            return copy(fromPath, dir.getAbsolutePath());
        } else {
            return 0;
        }
    }

    /**
     * 判断 so 文件是否存在
     */
    public static boolean isLoadSoFile(File dir, Boolean isExist) {
        File[] currentFiles;
        currentFiles = dir.listFiles();
        boolean hasSoLib = false;
        if (currentFiles == null) {
            return false;
        }
        for (File currentFile : currentFiles) {
            //判断里面是否存在这个库,以及sd也有这个库,那就删除,然后进行外面拷贝进去
            if (currentFile.getName().contains(nameSO)) {
                hasSoLib = isExist && !currentFile.delete();
            }
        }
        return hasSoLib;
    }

    public static int copy(String fromFile, String toFile) {
        //要复制的文件目录
        File[] currentFiles;
        File root = new File(fromFile);
        //如同判断SD卡是否存在或者文件是否存在,如果不存在则 return出去
        if (!root.exists()) {
            return -1;
        }
        //如果存在则获取当前目录下的全部文件 填充数组
        currentFiles = root.listFiles();

        if (currentFiles == null) {
            return -1;
        }
        //目标目录
        File targetDir = new File(toFile);
        //创建目录
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }

        int statue = -1;
        //遍历要复制该目录下的全部文件
        for (File currentFile : currentFiles) {
            if (currentFile.isDirectory()) {
                //如果当前项为子目录 进行递归
                copy(currentFile.getPath() + "/", toFile + currentFile.getName() + "/");
            } else {
                //如果当前项为文件则进行文件拷贝
                if (currentFile.getName().contains(".so")) {
                    statue = copySdcardFile(currentFile.getPath(), toFile + File.separator + currentFile.getName());
                }
            }
        }
        return statue;
    }


    //文件拷贝
    //要复制的目录下的所有非子目录(文件夹)文件拷贝
    public static int copySdcardFile(String fromFile, String toFile) {
        try {
            FileInputStream fosfrom = new FileInputStream(fromFile);
            FileOutputStream fosto = new FileOutputStream(toFile);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = fosfrom.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            // 从内存到写入到具体文件
            fosto.write(baos.toByteArray());
            // 关闭文件流
            baos.close();
            fosto.close();
            fosfrom.close();
            return 0;
        } catch (Exception ex) {
            return -1;
        }
    }
}
//ndk兼容 是用来动态加载so库  放到 android {}里面 
ndk {
    abiFilters("armeabi", "armeabi-v7a", "x86")
}


下面两行放到android.mk文件中

TARGET_CPU_API := armeabi
APP_ABI := armeabi

   友情提示:  APK中无需再放置 授权的SO 文件  直接通弄过代码复制到指定文件 直接调用就可以 

如果机器没有ROOT可以 自己下载一个re文件管理器  查看 文件是否复制成功 

整体流程就那么多 有疑问 大家可以留言 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值