在Flutter中使用Install_Plugin安装APK

前言

在开发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>

下载APK

  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

安装APK

  • ANDROID
  _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,所以可能需要考虑使用应用市场的安装方式。

  • IOS
  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的内容,欢迎在评论区留言。

在现有的 Flutter Kotlin 项目中实现安装 APK 的插件,可按以下步骤操作: ### 1. 创建插件项目 借助 Flutter 命令行工具创建插件项目: ```bash flutter create --template=plugin --platforms=android -a kotlin your_plugin_name ``` 此命令会生成一个包含 Android 平台(使用 Kotlin)的 Flutter 插件项目。 ### 2. 编写 Android 端代码 在 `android/src/main/kotlin` 目录下找到对应的 Kotlin 文件(通常为 `YourPluginNamePlugin.kt`),添加安装 APK 的逻辑。以下是示例代码: ```kotlin package com.example.your_plugin_name import android.content.Intent import android.net.Uri import android.os.Build import androidx.core.content.FileProvider import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result import java.io.File class YourPluginNamePlugin : FlutterPlugin, MethodCallHandler { private lateinit var channel: MethodChannel private var applicationContext: android.content.Context? = null override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "your_plugin_name") channel.setMethodCallHandler(this) applicationContext = flutterPluginBinding.applicationContext } override fun onMethodCall(call: MethodCall, result: Result) { if (call.method == "installApk") { val apkPath = call.argument<String>("apkPath") if (apkPath != null) { installApk(apkPath, result) } else { result.error("ARGUMENT_ERROR", "apkPath is null", null) } } else { result.notImplemented() } } private fun installApk(apkPath: String, result: Result) { val file = File(apkPath) if (file.exists()) { val intent = Intent(Intent.ACTION_VIEW) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION val contentUri = FileProvider.getUriForFile( applicationContext!!, "${applicationContext!!.packageName}.fileprovider", file ) intent.setDataAndType(contentUri, "application/vnd.android.package-archive") } else { intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive") } intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) applicationContext!!.startActivity(intent) result.success(null) } else { result.error("FILE_NOT_FOUND", "APK file not found", null) } } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) applicationContext = null } } ``` ### 3. 配置 AndroidManifest.xml 在 `android/src/main` 目录下的 `AndroidManifest.xml` 文件中添加以下内容: ```xml <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> ``` 同时,在 `res/xml` 目录下创建 `file_paths.xml` 文件,内容如下: ```xml <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths> ``` ### 4. 编写 Dart 端代码 在 `lib` 目录下的 Dart 文件(通常为 `your_plugin_name.dart`)中添加以下代码: ```dart import 'package:flutter/services.dart'; class YourPluginName { static const MethodChannel _channel = MethodChannel('your_plugin_name'); static Future<void> installApk(String apkPath) async { await _channel.invokeMethod('installApk', {'apkPath': apkPath}); } } ``` ### 5. 在 Flutter 项目中使用插件 在 `pubspec.yaml` 文件中添加插件依赖: ```yaml dependencies: your_plugin_name: path: ../your_plugin_name ``` 然后在 Flutter 代码中调用插件: ```dart import 'package:flutter/material.dart'; import 'package:your_plugin_name/your_plugin_name.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Install APK Plugin Example'), ), body: Center( child: ElevatedButton( onPressed: () async { try { await YourPluginName.installApk('/path/to/your/app.apk'); } catch (e) { print('Error: $e'); } }, child: const Text('Install APK'), ), ), ), ); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值