在开发Flutter应用时,有时候我们需要实现在应用内部安装APK的功能。众所周知,Android 7.0以后由于改变了文件URI的访问方式,我们需要使用FileProvider来创建一个content://URI来授予临时访问权限。
Flutter不同与原生,在Flutter中要么自己手写插件调用原生代码进行安装APK,要么找个第三方库来实现该功能,本人能力有限就简单介绍并使用本文的主角install_plugin
来实现该功能吧。
首先,你需要在你的pubspec.yaml文件中添加install_plugin的依赖:
dependencies:
install_plugin: ^2.1.0
然后执行flutter pub get获取依赖。
去官网查看最新版本 >>> https://pub.dev/packages/install_plugin
<!-- read permissions for external storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- installation package permissions -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- write permissions for external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在Android 7.0(API级别24)以后,由于改变了文件URI的访问方式,为了应用间共享文件,如安装APK,需要使用FileProvider来创建一个content://URI来授予临时访问权限。
在项目中的android/app/src/main/AndroidManifest.xml文件中的标签内添加配置,如下:
<application ...>
...
<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>
<!-- ${applicationId}会被替换为你的应用ID -->
<!-- android:resource="@xml/file_paths"指定了存放共享文件路径的资源文件。 -->
</application>
接下来,在android/app/src/main/res/目录下创建xml文件夹(有则不用创建),然后在xml文件夹下创建file_paths.xml文件,指定共享文件的路径:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<root-path name="root" path="" />
<files-path name="files" path="" />
<cache-path name="cache" path="" />
<external-path name="external" path="" />
<external-files-path name="external_files" path="" />
<external-cache-path name="external_cache" path="" />
</paths>
</resources>
Future<void> _download() async {
try {
setInitDir(initStorageDir: true);
await DirectoryUtil.getInstance();
DirectoryUtil.createStorageDirSync(category: 'Download');
final String path = DirectoryUtil.getStoragePath(
fileName: 'my', category: 'Download', format: 'apk') ?? '';
Log('_download path -> $path ');//path -> storage/emulated/0/Android/data/com.xxx.xxx/files/Download/my.apk
final File file = File(path);
/// 链接可能会失效
await Dio().download(
'http://imtt.dd.qq.com/16891/apk/FF9625F40FD26F015F4CDED37B6B66AE.apk',
file.path,
cancelToken: _cancelToken,
onReceiveProgress: (int count, int total) {
if (total != -1) {
//更新界面进度
_value = count / total;
setState(() {});
if (count == total) {
_installApk(path);
}
}
},
);
} catch (e) {
XToast.show('下载失败!');
debugPrint(e.toString());
setState(() {
_isDownload = false;
});
}
}
此处初始化存储文件路径使用的工具类库是:https://github.com/Sky24n/flustars
_installApk(String path) {
//换成你的apk包名
InstallPlugin.installApk(path, appId: 'com.xxx.xxx.fileprovider')
.then((result) {
print('install apk $path success: $result');
}).catchError((error) {
print('install apk $path fail: $error');
});
}
注意: 以上流程仅在Android中有效,iOS不支持此操作。另外,如果你的应用是从Google Play商店下载的,Google可能会阻止用户从应用内部安装APK,所以可能需要考虑使用应用市场的安装方式。
final String _defaultUrl = 'https://itunes.apple.com/cn/app/%E5%86%8D%E6%83%A0%E5%90%88%E4%BC%99%E4%BA%BA/id1375433239?l=zh&ls=1&mt=8';
///跳转苹果应用商店
_gotoAppStore(String url) async {
url = url.isEmpty ? _defaultUrl : url;
final res = await InstallPlugin.install(url);
Log(
"go to appstroe ${res['isSuccess'] == true ? 'success' : 'fail:${res['errorMessage'] ?? ''}'}");
}
打完收工!
这就是关于如何在Flutter中使用install_plugin插件进行APK安装的简单介绍。希望对你有所帮助。如果你有任何问题或者想要了解更多关于Flutter的内容,欢迎在评论区留言。