Android12适配 Targeting R+(version 30 and above) requires the resources.arsc of installed APKs t...

在使用命令行打包apk时,由于命令行打包直接将resources.arsc进行压缩,会导致这个问题出现,从而在android11及Android12版本的机型上无法安装,提示信息为:解析安装包出错,或者是Targeting R+(version 30 and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary]错误

在Android 11以及Android12 版本,对resources.arsc文件需要进行对齐,并且不压缩,

源码路径为 framework/base/core/java - android.content.pm.parsing.ParsingPackageUtils

    private ParseResult parseBaseApk(ParseInput input, File apkFile,
            String codePath, SplitAssetLoader assetLoader, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
        }

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final AssetManager assets = assetLoader.getBaseAssetManager();
        final int cookie = assets.findCookieForPath(apkPath);
        if (cookie == 0) {
            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }

        try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
                ANDROID_MANIFEST_FILENAME)) {
            final Resources res = new Resources(assets, mDisplayMetrics, null);

            ParseResult result = parseBaseApk(input, apkPath, codePath, res,
                    parser, flags);
            if (result.isError()) {
                return input.error(result.getErrorCode(),
                        apkPath + " (at " + parser.getPositionDescription() + "): "
                                + result.getErrorMessage());
            }

            final ParsingPackage pkg = result.getResult();
            //判断resources.arsc文件是否被压缩且是否用zipalign对齐过,如果资源resources.arsc被压缩了,或者没有用zipalign对齐,那么就会抛出这 
            //个异常
            if (assets.containsAllocatedTable()) {
                final ParseResult deferResult = input.deferError(
                        "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                                + " the resources.arsc of installed APKs to be stored uncompressed"
                                + " and aligned on a 4-byte boundary",
                        DeferredError.RESOURCES_ARSC_COMPRESSED);
                if (deferResult.isError()) {
                    return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                            deferResult.getErrorMessage());
                }
            }

            ApkAssets apkAssets = assetLoader.getBaseApkAssets();
            boolean definesOverlayable = false;
            try {
                definesOverlayable = apkAssets.definesOverlayable();
            } catch (IOException ignored) {
                // Will fail if there's no packages in the ApkAssets, which can be treated as false
            }

            if (definesOverlayable) {
                SparseArray packageNames = assets.getAssignedPackageIdentifiers();
                int size = packageNames.size();
                for (int index = 0; index < size; index++) {
                    String packageName = packageNames.valueAt(index);
                    Map overlayableToActor = assets.getOverlayableMap(packageName);
                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                        for (String overlayable : overlayableToActor.keySet()) {
                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                        }
                    }
                }
            }

            pkg.setVolumeUuid(volumeUuid);

            if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                pkg.setSigningDetails(getSigningDetails(pkg, false));
            } else {
                pkg.setSigningDetails(SigningDetails.UNKNOWN);
            }

            return input.success(pkg);
        } catch (Exception e) {
            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        }
    }
    /**
     * Returns whether the {@code resources.arsc} of any loaded apk assets is allocated in RAM
     * (not mmapped).
     *
     * @hide
     */
    public boolean containsAllocatedTable() {
        synchronized (this) {
            ensureValidLocked();
            return nativeContainsAllocatedTable(mObject);
        }
    }

所以,如果是使用命令行去打包,且target是Android11以后的版本,那么在安装到Android11以及Android12机型,就会出现以上的问题。

解决方法是,在压缩的使用,判断是否是resources.arsc ,则不进行压缩,使用ZipEntry.STORED方式保存

        if ("resources.arsc".equals(file.getName())){
            entry.setMethod(ZipEntry.STORED);
            entry.setSize(file.length());
            entry.setCompressedSize(-1);
            BufferedInputStream unknownFile = new BufferedInputStream(new FileInputStream(file));
            CRC32 crc = calculateCrc(unknownFile);
            entry.setCrc(crc.getValue());
        }

你可能感兴趣的:(Android12适配 Targeting R+(version 30 and above) requires the resources.arsc of installed APKs t...)