我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android基础——动态加载so库

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android基础——动态加载so库

Android中动态加载so

原因:如果把so文件直接放在libs目录下,在android程序启动的时候会默认加载libs目录下的所有so库,但这些so库可能会在某些地方存在冲突,使用动态加载so库,就可以通过一些条件判断是否要加载这个so库。
介绍:so的动态加载是把so库打包成apk的时候剔除,在合适的时候通过网络包下载的方式,在运行的时候进行分离加载。
优点:so文件是动态加载的,不是绑定死的,更便于修改,在so库有问题的时候可以动态更新;
so库文件动态加载可以极大地减小apk包的体积;
解决多个第三方库文件同时加载可能出现冲突的问题。

一、Android的so库文件的加载

  1. Android中加载so:
    (1)调用load()方法,传递so文件的绝对路径;
    (2)调用loadLibrary()方法,传递so文件的名称,而且so文件必须放在apk的lib目录下,而且so的名称必须去掉前面的lib和后边的“.so”。
    只能加载两个目录下的so文件:
    (1)/system/lib
    (2)应用程序安装包的路径:/data/data/packgename/…
    对于两种加载so文件的方法,在Android源码System.java中可以看到
    源码链接
    public static void load(String filename) {        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);    }
        public static void loadLibrary(String libname) {        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);    }
  1. 上边两种方法都调用了Runtime中的getRuntime函数,用来获取Runtime的实例
    源码链接
    public static Runtime getRuntime() {        return currentRuntime;    }
  1. 在加载so时也调用了loadLibrary0方法
    源码链接
    在loadLibrary0中可以看到根据ClassLoader是否为空,有两种不同的处理形式。
    private synchronized void loadLibrary0(ClassLoader loader, Class callerClass, String libname) {        if (libname.indexOf((int)File.separatorChar) != -1) {            throw new UnsatisfiedLinkError(    "Directory separator should not appear in library name: " + libname);        }        String libraryName = libname;        //ClassLoader不为空时(程序中通过System.loadlibrary()方式,这个loader就不会为空)        if (loader != null && !(loader instanceof BootClassLoader)) {        //通过ClassLoader的findLibrary方法查找so的文件名称,寻找so文件是否存在            String filename = loader.findLibrary(libraryName);            //判断,如果未找到so文件,并且类加载器存在            if (filename == null &&                    (loader.getClass() == PathClassLoader.class ||                     loader.getClass() == DelegateLastClassLoader.class)) {                filename = System.mapLibraryName(libraryName);//拼接so文件名            }            if (filename == null) {                throw new UnsatisfiedLinkError(loader + " couldn't find \"" +                   System.mapLibraryName(libraryName) + "\"");            }            //so文件存在,加载它            String error = nativeLoad(filename, loader);            if (error != null) {            //加载异常,加载失败                throw new UnsatisfiedLinkError(error);            }            return;        }        //ClassLoader为空时,传入library name和System.mapLibraryName获得真正的library name。        //具体深入的实现过程,可以到Android源码继续查看getLibPaths()和mapLibraryName的实现        getLibPaths();        String filename = System.mapLibraryName(libraryName);//mapLibraryName用于拼接so文件名的前缀:lib和后缀.so        //例如传入的是wudong,得到的就会是libwudong.so,然后在mLibPaths查找'libwudong.so',最终确定library的path。        String error = nativeLoad(filename, loader, callerClass);        if (error != null) {//加载异常            throw new UnsatisfiedLinkError(error);        }    }
  1. 在查找so文件的过程中,调用了loader.findLibrary的方法去寻找so文件,如果可以找到,会返回so文件的绝对路径,然后交由nativeLoad()去加载。

二、实现so的动态加载

首先把so库放在assets资源目录下,一般会放两个so库,一个32位一个64位的;
2.动态加载,就是在需要使用的时候,从assets资源目录下复制到app/libs目录下;
3.通过 System.load(String filename) 或者 System.loadLibrary(String libname) 方法去加载 so。
·在so原本的加载过程中,是系统通过ClassLoader检索native目录里是否存在so库进行加载的,那就需要把下载存放so的路径添加到ClassLoader的libs路径里,这些libs路径在app启动的时候就已经生成了,那就需要利用反射,在运行时把路径添加进去。

将存放so的路径放到ClassLoader中

利用反射将存放so的路径放到ClassLoader中,开源项目tinker的TinkerLoadLibrary也有实现发方法,我们就不用自己实现了,可以拿过来直接使用。

private static final class V25 {        private static void install(ClassLoader classLoader, File folder)  throws Throwable {            final Field pathListField = ShareReflectUtil.findField(classLoader, "pathList");            final Object dexPathList = pathListField.get(classLoader);            final Field nativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "nativeLibraryDirectories");            List origLibDirs = (List) nativeLibraryDirectories.get(dexPathList);            if (origLibDirs == null) {                origLibDirs = new ArrayList<>(2);            }            final Iterator libDirIt = origLibDirs.iterator();            while (libDirIt.hasNext()) {                final File libDir = libDirIt.next();                if (folder.equals(libDir)) {                    libDirIt.remove();                    break;                }            }            origLibDirs.add(0, folder);            final Field systemNativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "systemNativeLibraryDirectories");            List origSystemLibDirs = (List) systemNativeLibraryDirectories.get(dexPathList);            if (origSystemLibDirs == null) {                origSystemLibDirs = new ArrayList<>(2);            }            final List newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);            newLibDirs.addAll(origLibDirs);            newLibDirs.addAll(origSystemLibDirs);            final Method makeElements = ShareReflectUtil.findMethod(dexPathList, "makePathElements", List.class);            final Object[] elements = (Object[]) makeElements.invoke(dexPathList, newLibDirs);            final Field nativeLibraryPathElements = ShareReflectUtil.findField(dexPathList, "nativeLibraryPathElements");            nativeLibraryPathElements.set(dexPathList, elements);        }    }}

这样路径就可以添加进ClassLoader的nativeLibraryDirectories中了。

来源地址:https://blog.csdn.net/weixin_44901971/article/details/127557644

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android基础——动态加载so库

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android基础——动态加载so库

Android中动态加载so 原因:如果把so文件直接放在libs目录下,在android程序启动的时候会默认加载libs目录下的所有so库,但这些so库可能会在某些地方存在冲突,使用动态加载so库,就可以通过一些条件判断是否要加载这个so
2023-08-17

Android将so库封装到jar包中并加载其中的so库

Android将so库封装到jar包中并加载其中的so库 之前写过将jar包和so库封装到jar包中的文章,但是没有考虑别人调用时需要加载so库的问题。因为so库放入jar之后,so就不是一个独立的.so文件了,用System.load()
2022-06-06

Android动态加载布局

ListView我们一直都在用,只不过当Adapter中的内容比较多的时候我们有时候没办法去设置一些组件,举个例子:可以看到京东的故事里面的这样一个布局,这个布局可以说是我目前见到的内容比较多的了,它的每一项都包含头像、姓名、分类、内容、图
2022-06-06

Android ViewPager动态加载问题

今天做项目时,纠结了很久,动态添加view,刚开始按照其他的adapter处理,但是不会刷新view,来回翻几页,还会view覆盖,最后手动调用adapter的destroyItem和instantiateItem方法,还是不行,最后重写n
2022-06-06

android调用JNI SO动态库的方法是什么

这篇文章主要介绍“android调用JNI SO动态库的方法是什么”,在日常操作中,相信很多人在android调用JNI SO动态库的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”android调用
2023-06-25

linux生成(加载)动态库静态库和加载示例方法

动态库的生成: 1、#include #include "src.h" int sum(int a,int b){return (a+b);}2、#ifndef __SRC_H_
2022-06-04

C#中怎么加载动态库

这期内容当中小编将会给大家带来有关C#中怎么加载动态库,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。C#语言有很多值得学习的地方,这里我们主要介绍C#实现加载动态库,包括介绍将 C 或 C++ 函数封装成
2023-06-17

Android动态加载Activity原理详解

activity的启动流程 加载一个Activity肯定不会像加载一般的类那样,因为activity作为系统的组件有自己的生命周期,有系统的很多回调控制,所以自定义一个DexClassLoader类加载器来加载插件中的Activity肯定是
2022-06-06

Android应用开发中Fragment的静态加载与动态加载实例

1、Fragment的静态使用 Fragment是作为Activity的UI的一部分,它内嵌在Activity中,多个Fragment可以把一个Activity分成多个部分,这在大屏幕手机或者平板电脑中会比较多的用到,这样就不用使用多个Ac
2022-06-06

Android应用中如何动态加载ViewPager

本篇文章为大家展示了Android应用中如何动态加载ViewPager,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。今天做项目时,纠结了很久,动态添加view,刚开始按照其他的adapter处理,但
2023-05-31

Android插件化之资源动态加载

Android插件化之资源动态加载一.概述Android插件化的一个重要问题就是插件资源访问问题,先列出会面对的问题1.如何加载插件资源 2.如何处理插件资源与宿主资源的处突:插件化资源问题要做到的效果是,如果我们要获取的资源在插件中找得到
2022-06-06

android动态加载布局文件示例

一、布局文件part.xml:代码如下:2022-06-06

Android动态加载资源实例解析

前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的。从高德官方导航 javascript:;" onClick="javascript:tagshow(event, 'API
2022-06-06

C++使用宏实现动态库加载

开发的时候,有些项目不能静态链接动态库,需要程序运行时加载动态库。本文将使用宏来实现动态库的加载,感兴趣的小伙伴可以跟随小编一起了解一下
2022-12-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录