android 5.0 apk 安装失败提示INSTALL_FAILED_INVALID_URI

在android 5.0 项目上开发的时候,进入U盘目录,通过pm 命令安装apk,发现安装失败,提示apk路径不对。

安装log信息如下:

cd /mnt/usb/2D80-E3ED/APK_backup

shell@yjw:/mnt/usb/2D80-E3ED/APK_backup # pm install AndyKeyTest.apk      
        pkg: AndyKeyTest.apk
Failure [INSTALL_FAILED_INVALID_URI]

logcat信息:

01-01 08:20:49.955 D/AndroidRuntime( 2952): Calling main entry com.android.commands.pm.Pm
01-01 08:20:49.968 W/asset   ( 2734): Asset path /AndyKeyTest.apk is neither a directory nor file (type=1).
--------- beginning of system
01-01 08:20:49.968 W/DefContainer( 2734): Failed to parse package at /AndyKeyTest.apk: android.content.pm.PackageParser$PackageParserException: Failed to parse /AndyKeyTest.apk


通过log信息及测试发现,原来在android5.0中不能直接在u盘目录下执行pm install 安装apk ,必须到要在pm 命令带上apk所在路劲。更早的android版本没有这个要求

改为在根目录下,执行下面命令,则安装apk成功

shell@yjw:/ # pm install mnt/usb/2D80-E3ED/APK_backup/AndyKeyTest.apk
       pkg: mnt/usb/2D80-E3ED/APK_backup/AndyKeyTest.apk
Success


针对上面的问题,查看了一下源码,发现android 5.0 的parsePackage功能在细节上有一些更改,所以出现上面的情况。

相关代码如下:

PackageParser.java@

    /**
     * Parse only lightweight details about the package at the given location.
     * Automatically detects if the package is a monolithic style (single APK
     * file) or cluster style (directory of APKs).
     * <p>
     * This performs sanity checking on cluster style packages, such as
     * requiring identical package name and version codes, a single base APK,
     * and unique split names.
     *
     * @see PackageParser#parsePackage(File, int)
     */
    public static PackageLite parsePackageLite(File packageFile, int flags)
            throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackageLite(packageFile, flags);
        } else {
            return parseMonolithicPackageLite(packageFile, flags);
        }
    }


DefaultContainerService.java@

        /**
         * Parse given package and return minimal details.
         *
         * @param packagePath absolute path to the package to be copied. Can be
         *            a single monolithic APK file or a cluster directory
         *            containing one or more APKs.
         */
        @Override
        public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
                String abiOverride) {
            final Context context = DefaultContainerService.this;
            final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;

            PackageInfoLite ret = new PackageInfoLite();
            if (packagePath == null) {
                Slog.i(TAG, "Invalid package file " + packagePath);
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                return ret;
            }

            final File packageFile = new File(packagePath);
            final PackageParser.PackageLite pkg;
            final long sizeBytes;
            try {
                pkg = PackageParser.parsePackageLite(packageFile, 0);
                sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
            } catch (PackageParserException | IOException e) {
                Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);

                if (!packageFile.exists()) {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
                } else {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                }

                return ret;
            }

            ret.packageName = pkg.packageName;
            ret.versionCode = pkg.versionCode;
            ret.installLocation = pkg.installLocation;
            ret.verifiers = pkg.verifiers;
            ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
                    pkg.packageName, pkg.installLocation, sizeBytes, flags);
            ret.multiArch = pkg.multiArch;

            return ret;
        }


<think>好的,用户遇到了安装APK时报错INSTALL_FAILED_INVALID_APK,具体原因是无法提取原生库,错误代码res=-2。我需要帮他分析这个问题。首先,这个错误通常和APK中的原生库(SO文件)有关,可能的原因包括压缩问题、路径错误、签名问题或者ABI兼容性。 用户之前的问题是关于用IDA修改SO文件并重打包的流程,所以这次错误很可能是在修改SO后重打包时出现的。可能他在重打包过程中某些步骤没做对,比如没有正确替换SO文件,或者压缩了SO文件导致系统无法提取。 接下来,我要考虑常见的解决方法。首先检查APK中的lib目录结构是否正确,SO文件是否放在正确的架构子目录下,比如arm64-v8a或armeabi-v7a。然后确认在打包时没有启用压缩,因为Android安装时如果发现SO文件被压缩,会报这个错误。可以通过在APKTOOL的配置中添加-0 so来禁止压缩。 另外,签名是否正确也很重要,虽然错误信息可能不直接提示签名问题,但签名失败也可能导致安装问题。还要检查SO文件本身是否有效,比如是否被正确修改,没有损坏。如果有多个ABI版本,可能需要检查是否某些架构的目录有问题。 用户可能需要逐步排查,比如用解压工具检查APK内的SO文件路径和压缩情况,确认打包命令是否正确,签名步骤是否正确。另外,使用Android Studio的分析APK功能可能更直观,或者用命令行工具检查压缩参数。 需要注意用户可能不太熟悉APK打包的细节,特别是修改SO后的处理,所以步骤要详细,可能需要具体命令和示例。另外,用户可能是在修改SO后没有正确配置APKTOOL的打包选项,导致SO被压缩,需要明确告诉他在打包时如何禁用压缩。</think>以下是针对安装报错 **`Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2]`** 的详细分析和解决方案: --- ### **一、错误原因** 此错误表示 **APK中的原生库(SO文件)无法被系统正确提取**,常见原因包括: 1. **SO文件被压缩**:Android要求原生库(SO文件)在APK中必须以**未压缩形式存储**。若打包时SO文件被压缩(如ZIP Deflate算法),会导致系统无法解压。 2. **SO文件路径错误**:SO文件未放置在APK的`lib/<abi>/`目录下(如`lib/arm64-v8a/`),或文件名不符合规范。 3. **APK签名冲突**:重打包后未正确签名,或签名证书与原APK不一致。 4. **SO文件损坏**:修改SO文件时导致格式错误或ABI不兼容。 --- ### **二、解决方案** #### **1. 检查SO文件压缩状态** - **验证方法**: - 使用解压工具(如7-Zip)打开APK,检查`lib/<abi>/`中的SO文件: - **正常状态**:SO文件应显示为`Stored`(未压缩)。 - **异常状态**:若显示`Deflated`,则说明被压缩。 - **修复方法**: - **使用Apktool时**:在打包命令中添加`-0 so`参数,禁止压缩SO文件: ```bash apktool b input_dir -o output.apk --use-aapt2 -0 so ``` - **手动配置**:在`apktool.yml`中添加以下配置: ```yaml doNotCompress: - so ``` --- #### **2. 检查SO文件路径和架构** - **路径规范**: - 确保SO文件位于`lib/arm64-v8a/`、`lib/armeabi-v7a/`等标准ABI目录下。 - **错误示例**:SO文件直接放在`lib/`根目录或子目录名称拼写错误(如`arm64v8a`)。 - **架构兼容性**: - 检查设备支持的ABI(通过`adb shell getprop ro.product.cpu.abi`),确保APK包含对应架构的SO文件。 --- #### **3. 验证APK签名** - **重新签名APK**: ```bash apksigner sign --ks your.keystore --ks-key-alias alias_name output.apk ``` - 使用`jarsigner`时需指定签名算法: ```bash jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore your.keystore output.apk alias_name ``` --- #### **4. 检查SO文件完整性** - **IDA修改后的验证**: - 若修改过SO文件,需确保: 1. 指令长度未破坏对齐(如ARM架构要求4字节对齐)。 2. 未删除/覆盖关键函数或数据段。 3. 使用`readelf -a libtarget.so`检查文件头是否正常。 - **替换原始SO文件**: - 若不确定修改是否导致损坏,可尝试用原始未修改的SO文件重打包测试。 --- #### **5. 其他可能原因** - **AndroidManifest.xml配置错误**: - 检查是否声明了`android:extractNativeLibs="true"`(建议设置为`false`,但需确保SO未压缩)。 - **APK安装来源限制**: - 允许安装未知来源应用(设置 → 安全 → 启用“未知来源”)。 --- ### **三、调试工具推荐** 1. **Android Studio → Build → Analyze APK** 直接查看APK内文件压缩状态和路径。 2. **Zipdetails** 命令行工具分析APK压缩方式: ```bash zipdetails -v modified.apk | grep "lib/.*\.so" ``` 3. **ADB Logcat** 过滤安装过程日志: ```bash adb logcat | grep "PackageManager" ``` --- ### **四、总结** | 步骤 | 操作 | 检查点 | |------|------|--------| | 1 | 检查SO压缩状态 | 确保SO文件为`Stored` | | 2 | 验证SO路径 | 符合`lib/<abi>/`结构 | | 3 | 重新签名APK | 使用`apksigner`或`jarsigner` | | 4 | 替换为原始SO | 排除文件损坏可能性 | 通过以上步骤,可解决90%的`INSTALL_FAILED_INVALID_APK: Failed to extract native libraries`问题。若仍无法解决,需检查设备兼容性或APK加固措施。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值