Flutter Android端如何实现点击按钮分享应用APK安装包
Flutter Android端实现APK分享功能实现方案
核心实现逻辑:通过系统接口拿到当前应用自身的APK真实存储路径,适配安卓高版本文件访问规则后,调用系统分享组件拉起包括Xender在内的所有支持文件传输的应用,iOS端直接屏蔽逻辑即可,不需要额外适配。
1. 引入所需依赖
打开项目根目录的pubspec.yaml,在dependencies节点下添加以下依赖,版本可以直接用pub上的最新稳定版,不用刻意锁死下面写的版本号:
dependencies: flutter: sdk: flutter share_plus: ^7.2.2 # 系统分享能力封装 path_provider: ^2.1.2 # 应用目录访问 package_info_plus: ^5.0.1 # 获取应用版本号,用于给分享的APK重命名
保存后执行flutter pub get拉取依赖。
2. Android端原生配置
这步必须做,否则安卓7.0及以上版本会因为文件Uri暴露规则直接崩溃。
- 打开
android/app/src/main/AndroidManifest.xml,在<application>标签内部添加FileProvider配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
- 在
android/app/src/main/res目录下新建xml文件夹,在文件夹内创建file_paths.xml文件,写入以下配置,给分享操作开放路径访问权限:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> <cache-path name="cache" path="."/> <files-path name="files" path="."/> </paths>
- 配置方法通道拿APK真实路径:打开对应包名路径下的
MainActivity文件,添加方法通道回调,直接返回系统提供的APK路径,比自己遍历目录找文件靠谱100%。
如果是Kotlin写的MainActivity,代码如下:
如果是Java写的MainActivity,逻辑完全一致,重写// 记得导入对应依赖包 class MainActivity: FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "apk_share_channel").setMethodCallHandler { call, result -> if (call.method == "get_apk_path") { // 系统接口直接返回当前安装APK的真实路径,全版本通用 result.success(applicationContext.packageCodePath) } else { result.notImplemented() } } } }configureFlutterEngine方法,在回调里返回getApplicationContext().getPackageCodePath()即可。
注意:整个过程不需要申请任何存储权限,所有路径访问都在应用自身权限范围内,符合安卓最新的权限规范,不会触发合规问题。
3. 编写Flutter端分享逻辑
在需要放分享功能的页面对应的dart文件里,写入以下方法:
import 'dart:io'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:package_info_plus/package_info_plus.dart'; // 分享APK的核心方法 Future<void> shareApkFile() async { // 非Android端直接返回,不执行逻辑 if (!Platform.isAndroid) return; // 1. 通过方法通道拿原生返回的APK真实路径 const channel = MethodChannel('apk_share_channel'); String? originApkPath; try { originApkPath = await channel.invokeMethod('get_apk_path'); } catch (e) { // 拿路径失败直接返回,可自行加toast提示用户 return; } if (originApkPath == null || !File(originApkPath).existsSync()) return; // 2. 把APK复制到缓存目录,重命名为带版本号的文件名,方便接收方识别 final tempDir = await getTemporaryDirectory(); final packageInfo = await PackageInfo.fromPlatform(); final targetApk = File('${tempDir.path}/我的应用_v${packageInfo.version}.apk'); if (!targetApk.existsSync()) { await File(originApkPath).copy(targetApk.path); } // 3. 调用系统分享,自动拉起所有支持文件分享的应用,包括Xender、蓝牙、其他传输类APP await Share.shareXFiles( [XFile(targetApk.path, mimeType: 'application/vnd.android.package-archive')], text: '分享给你这款应用的安装包,点击即可安装', ); }
4. 添加分享按钮
在你需要放置按钮的位置插入组件,绑定点击事件即可:
ElevatedButton( onPressed: shareApkFile, child: const Text("分享"), )
踩坑提示
- 不要硬编码APK存储路径,不同厂商ROM、不同安卓版本的系统应用目录差异极大,硬编码大概率会出现找不到文件的问题,用系统接口返回的
packageCodePath是兼容性最好的方案 - FileProvider的
authorities必须和配置里的${applicationId}.fileprovider保持一致,不要随便写自定义值,否则会报权限错误 - 不要在复制APK的时候加多余的修改操作,直接字节复制就行,否则会导致APK签名损坏,接收方安装失败
- 分享时指定mimeType为
application/vnd.android.package-archive,能让系统正确识别这是APK安装包,避免部分传输类APP无法识别文件类型
内容的提问来源于stack exchange,提问作者Precious
相关产品推荐
相关产品推荐

