如何让安卓删除旧的本地库?

4
我正在尝试从我的应用程序中删除一些原生库,因为我不再使用它们,但是在我将apk安装到我的手机后,我可以看到这些原生库仍然存在。 据我所见,当我在libs/目录中替换文件时,Android确实会正确地复制/更新本机库,但显然当它们不再在apk中时,它不会删除它们。 如何知道库仍然存在?首先,应用程序的大小保持不变,而我正在删除一些非常大的库,其次,如果我留下System.load(...)语句,则应用程序仍能够加载库。
我找到的唯一解决方案是卸载该应用程序并进行全新安装,但对于从Google Play更新应用程序的用户来说,这不是一个明显的解决方案,并且是的,这个问题严重影响了我的应用程序功能。
我已经检查过了,显然我可以自己删除文件,例如在服务创建期间,但我不想以这种方式干扰安装。
你知道是否有一种方法告诉Android需要删除所有本地库并重新复制它们吗?
谢谢, Mike [编辑]
我刚刚发现GB正确更新库,删除了现在缺少的库,但ICS和JB都没有这样做,即使它们不再在apk中,这两个版本也会保留旧的.so文件。
我尝试手动从/data/data/mypackage/lib中删除.so文件,但它不允许我这样做。
有什么想法吗?

你也可以在应用程序上执行清除数据操作,但这将擦除存储在应用程序私有目录中的所有数据。但是,如果这些旧库的存在不会引起问题,那么它们就只是闲置而已。 - Gabe Sechan
听起来你的设备上可能有一个损坏的Android版本。你在模拟器上是否遇到了同样的问题?首先,应用程序代码不应该有权限修改其lib/文件夹的内容,因此如果您可以这样做,那么这本身就表明了一些非标准的东西。我很好奇如果你创建一个升级apk,并使用一个名字相同的零长度.so文件来覆盖你想要清除的文件会发生什么。另外,你可能想要使用adb shell中的run-as your.package.name命令,然后ls -l lib,看看实际安装了什么。 - Chris Stratton
问题在于加载这些库的类不是我的,所以我无法阻止它们从Java中被加载。 - mike.adc
如果您的应用程序中的代码正在尝试加载它们,删除它们可能会导致运行时异常。您需要删除依赖于它们的代码,或者以适当的方式创建带有每个本地方法的虚拟版本的存根库,这些虚拟版本不执行任何操作。或者全局捕获这些异常并进行恢复。 - Chris Stratton
事实上,@ChrisStratton,我没有尝试通过代码删除库,我只是读到了这种可能性,但我不想使用那个选项。我还尝试用名字相同的空文件替换.so文件,但应用程序会崩溃,并显示“致命信号7”错误,这在Java中无法捕获,因为它不是异常。 - mike.adc
不,我可以安全地删除它们,因为这些库是可选的,如果它们没有找到,功能将被禁用,并且这些是我不需要的功能。 - mike.adc
2个回答

4

好的,所以我放弃了安卓并自己动手。我从这里获取了一些提示:http://www.moodstocks.com/2012/03/20/ice-cream-sandwich-why-native-code-support-sucks/

这是我所做的:

  1. Make three zip files with the contents of the folders libs/armeabi, libs/armeabi-v7a and libs/x86 and named them libs_armeabi.zip, libs_armeabi_v7a.zip and libs_x86.zip respecively.

  2. Move the zip files to the res/raw folder.

  3. Delete the files under the three libs folders and re-create them with touch (in a -nix system), remember that ICS and JB don't delete the old files in the lib folder, so just deleting the files would cause the app to keep those files which are quite large.

  4. Verify the processor architecture programmatically with these two methods:

    public static boolean isArmv7() {
        try {
            return Build.VERSION.SDK_INT >= 4 && Build.class.getField("CPU_ABI").get(null).toString().startsWith("armeabi-v7");
        } catch (Throwable e) {}
    
        return false;
    }
    
    public static boolean isX86() {
        try {
            return Build.VERSION.SDK_INT >= 4 && Build.class.getField("CPU_ABI").get(null).toString().startsWith("x86");
        } catch (Throwable e) {}
    
        return false;
    }
    
  5. Depending on the processor architecture unzip one of the three files programmatically to any folder you want, I'm using /data/data/myPackage/app_libs (using context.getDir("libs",Context.MODE_PRIVATE); returns that path).

也许这里涉及更多逻辑,例如提取libs_armeabi.zip文件,然后从libs_armeabi_v7a.zip或libs_x86.zip中提取文件,或者不提取任何文件,覆盖名称相同的文件(我只是在想象,因为我实际上并没有尝试过)。幸运的是,我的三个文件中的libs已经被重命名并且分别存储在每个zip文件中,因此我只需要提取其中之一。
将System.loadLibrary方法调用替换为System.load方法,它支持使用完整路径加载库,并为每个库添加完整路径。这种方法带来了以下好处:
- 由于库被压缩到apk中,应用在Google Play商店中的大小会更小。 - 由于库存储在原始资源内,Android不会自动复制它们,允许您将它们复制到任何位置并使用完整路径加载它们。 - 如果您想要,可以决定将库复制到SD卡中,但我不建议这样做,现在你有能力这样做了,例如当手机没有足够空间时。
希望这能帮到您!

如果我有一个应用程序,需要确定本地库和支持的本地架构,这个方法有帮助吗?该应用程序已安装,我正在使用另一个应用程序来检查构建。我的意思清楚吗? - Siddharthan Asokan
链接已失效。 - amitooshacham

0

本地 lib 目录中的所有文件的所有者都是 System。因此,在您的应用程序中,您无法在没有 root 权限的情况下删除这些文件。

将您的 lib 目录移动到 res/raw 中,然后手动将它们复制到内部数据是一个不错的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接