You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Android应用Release模式下jniLibs无法提取至nativeLibDirectory

Flutter Android Release模式下.so库未提取至nativeLibDirectory的解决方法

问题描述

我用Flutter开发了一款依赖jniLibs的Android应用,没用到ffi,而是通过Process.run直接从nativeLibDirectory调用.so库。Debug模式运行正常,但Release模式下会抛出Process异常,提示指定.so文件不存在。

解压发布的APK能看到所有库都在libs文件夹里,但安装后应用的nativeLibDirectory里找不到这些库(Debug模式下能正常提取)。

查资料知道这是Android 6引入的特性:原生库可以存在APK内不用解压,直接从APK加载,不需要复制到文件系统。我已经在AndroidManifest.xml里加了android:extractNativeLibs="true"但没用,也试过在build.gradle里加以下配置(包括组合配置),还是解决不了:

ndk {
    abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
}

// ---
packagingOptions {
    jniLibs {
        useLegacyPackaging = true
    }
}

// ---
sourceSets {
    main {
        jniLibs.srcDirs = ['libsrc/main/jniLibs']
    }
}

怎么强制Android把库提取到nativeLibDirectory,而不是只存在base.apk里?

解决方案

1. 修正AndroidManifest.xml里的extractNativeLibs配置

先检查application标签下的extractNativeLibs属性格式,别多套引号:

<application
    android:extractNativeLibs="true"
    ...>

之前如果写成"android:extractNativeLibs="true""这种格式,系统会识别不了这个属性,直接无效。

2. 在build.gradle里强制开启提取逻辑

在app/build.gradle的android块里加这些配置,确保打包时标记必须提取原生库:

android {
    ...
    defaultConfig {
        ...
        // 针对AGP 7.0+,明确传递提取参数到Manifest
        manifestPlaceholders = [extractNativeLibs: "true"]
    }

    packagingOptions {
        // 禁止剥离.so的调试符号,同时避免系统跳过提取
        jniLibs {
            doNotStrip "**/*.so"
        }
        // 强制用旧版打包逻辑,保证.so会被提取到文件系统
        jniLibs.useLegacyPackaging = true
    }
}
  • doNotStrip防止.so被优化剥离,同时让系统不会因为“可直接加载”而跳过提取
  • useLegacyPackaging强制使用传统的jniLibs打包方式,确保.so被放到能被提取的位置

3. 手动复制.so到可访问目录

如果上面的配置都没用,那就手动在应用启动时把APK里的.so复制到可读写目录(比如应用文档目录):
首先添加依赖到pubspec.yaml:

dependencies:
  archive: ^3.4.0
  package_info_plus: ^4.0.0
  path_provider: ^2.0.0

然后写提取逻辑:

import 'dart:io';
import 'package:archive/archive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:package_info_plus/package_info_plus.dart';

Future<void> extractSoFiles() async {
  final packageInfo = await PackageInfo.fromPackageName(await getPackageName());
  final apkPath = packageInfo.applicationInfo.sourceDir;
  final destDir = await getApplicationDocumentsDirectory();
  final destPath = destDir.path;

  // 读取APK文件
  final bytes = File(apkPath).readAsBytesSync();
  final archive = ZipDecoder().decodeBytes(bytes);

  // 遍历并提取所有.so文件
  for (final file in archive) {
    if (file.name.startsWith('lib/') && file.name.endsWith('.so')) {
      final fileName = file.name.split('/').last;
      final outputFile = File('$destPath/$fileName');
      if (!outputFile.existsSync()) {
        outputFile.writeAsBytesSync(file.content);
        // 给.so添加执行权限
        await Process.run('chmod', ['755', outputFile.path]);
      }
    }
  }
}

在应用启动时调用这个方法,之后就从destPath目录调用.so文件就行。

4. 检查Flutter的ABI过滤配置

确保Flutter打包时没过滤掉需要的ABI,在app/build.gradle里确认ndk.abiFilters和Flutter的目标平台一致:

android {
    ...
    buildTypes {
        release {
            ...
            ndk {
                abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
            }
        }
    }
}

同时在android/gradle.properties里添加:

flutter.targetPlatform=android-arm,android-arm64,android-x86,android-x64

内容的提问来源于stack exchange,提问作者Beer_belly 665

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:27:05